influxdb-client 1.2.0.pre.535 → 1.2.0.pre.562
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/README.md +2 -0
- data/lib/influxdb2/client/influx_error.rb +7 -3
- data/lib/influxdb2/client/worker.rb +33 -11
- data/lib/influxdb2/client/write_api.rb +31 -7
- data/test/influxdb/write_api_batching_test.rb +127 -1
- data/test/influxdb/write_api_test.rb +19 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5a1a523648c0252791755455bff70a6d2fddb7e6de8de793aa6e92871e9a76d
|
4
|
+
data.tar.gz: 804b8543ec36402c6fb62d361b83eec7a03c5b4d46e23d225171ba702aad07e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 060ec40dd8735238025978a3c404ab38f0ecaa90e894a06f22390cc83ff976820c42963e3a155fff9fc14b5b24d9c942ec2b2647d47e1a6aa15daf16ab4898c1
|
7
|
+
data.tar.gz: e6336c095161b4750603d2714dd67383d7c3340442be492d758f32a9ddb073e098f83879943e09fb164c82ac3734bde641750a1fa3281a62987179c5e9626a6d
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
### Features
|
4
4
|
1. [#23](https://github.com/influxdata/influxdb-client-ruby/issues/23): Added DeleteApi to delete time series data from InfluxDB.
|
5
|
+
1. [#24](https://github.com/influxdata/influxdb-client-ruby/issues/24): Added jitter_interval and retry_interval to WriteApi
|
5
6
|
|
6
7
|
### Bugs
|
7
8
|
1. [#22](https://github.com/influxdata/influxdb-client-ruby/pull/22): Fixed batch write
|
data/README.md
CHANGED
@@ -123,6 +123,8 @@ The writes are processed in batches which are configurable by `WriteOptions`:
|
|
123
123
|
| --- | --- | --- |
|
124
124
|
| **batchSize** | the number of data point to collect in batch | 1000 |
|
125
125
|
| **flushInterval** | the number of milliseconds before the batch is written | 1000 |
|
126
|
+
| **retry_interval** | the number of milliseconds to retry unsuccessful write. The retry interval is used when the InfluxDB server does not specify "Retry-After" header. | 1000 |
|
127
|
+
| **jitter_interval** | the number of milliseconds to increase the batch flush interval by a random amount | 0 |
|
126
128
|
|
127
129
|
```ruby
|
128
130
|
write_options = InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING,
|
@@ -5,22 +5,26 @@ module InfluxDB2
|
|
5
5
|
attr_reader :code
|
6
6
|
# Reference code unique to the error type
|
7
7
|
attr_reader :reference
|
8
|
+
# The Retry-After header describes when to try the request again.
|
9
|
+
attr_reader :retry_after
|
8
10
|
|
9
|
-
def initialize(message:, code:, reference:)
|
11
|
+
def initialize(message:, code:, reference:, retry_after:)
|
10
12
|
super(message)
|
11
13
|
|
12
14
|
@code = code
|
13
15
|
@reference = reference
|
16
|
+
@retry_after = retry_after
|
14
17
|
end
|
15
18
|
|
16
19
|
def self.from_response(response)
|
17
20
|
json = JSON.parse(response.body)
|
18
|
-
obj = new(message: json['message'] || '', code: response.code, reference: json['code'] || ''
|
21
|
+
obj = new(message: json['message'] || '', code: response.code, reference: json['code'] || '',
|
22
|
+
retry_after: response['Retry-After'] || '')
|
19
23
|
obj
|
20
24
|
end
|
21
25
|
|
22
26
|
def self.from_message(message)
|
23
|
-
obj = new(message: message, code: '', reference: '')
|
27
|
+
obj = new(message: message, code: '', reference: '', retry_after: '')
|
24
28
|
obj
|
25
29
|
end
|
26
30
|
end
|
@@ -33,24 +33,36 @@ module InfluxDB2
|
|
33
33
|
|
34
34
|
@thread_flush = Thread.new do
|
35
35
|
until api_client.closed
|
36
|
-
sleep @write_options.flush_interval / 1_000
|
37
|
-
|
36
|
+
sleep @write_options.flush_interval.to_f / 1_000
|
37
|
+
_check_background_queue
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
@thread_size = Thread.new do
|
42
42
|
until api_client.closed
|
43
|
-
|
43
|
+
_check_background_queue(size: true) if @queue.length >= @write_options.batch_size
|
44
44
|
sleep 0.01
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def push(payload)
|
50
|
-
|
50
|
+
if payload.respond_to? :each
|
51
|
+
payload.each do |item|
|
52
|
+
push(item)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
@queue.push(payload)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def flush_all
|
60
|
+
_check_background_queue until @queue.empty?
|
51
61
|
end
|
52
62
|
|
53
|
-
|
63
|
+
private
|
64
|
+
|
65
|
+
def _check_background_queue(size: false)
|
54
66
|
@queue_event.pop
|
55
67
|
data = {}
|
56
68
|
points = 0
|
@@ -74,20 +86,30 @@ module InfluxDB2
|
|
74
86
|
end
|
75
87
|
|
76
88
|
begin
|
77
|
-
|
89
|
+
_write(data) unless data.values.flatten.empty?
|
78
90
|
ensure
|
79
91
|
@queue_event.push(true)
|
80
92
|
end
|
81
93
|
end
|
82
94
|
|
83
|
-
def
|
84
|
-
|
95
|
+
def _write(data)
|
96
|
+
data.each do |key, points|
|
97
|
+
_write_raw(key, points)
|
98
|
+
end
|
85
99
|
end
|
86
100
|
|
87
|
-
def
|
88
|
-
|
89
|
-
@
|
101
|
+
def _write_raw(key, points)
|
102
|
+
if @write_options.jitter_interval.positive?
|
103
|
+
jitter_delay = (@write_options.jitter_interval.to_f / 1_000) * rand
|
104
|
+
sleep jitter_delay
|
90
105
|
end
|
106
|
+
@api_client.write_raw(points.join("\n"), precision: key.precision, bucket: key.bucket, org: key.org)
|
107
|
+
rescue InfluxError => e
|
108
|
+
raise e if e.code.nil? || !(%w[429 503].include? e.code)
|
109
|
+
|
110
|
+
timeout = e.retry_after.empty? ? @write_options.retry_interval.to_f / 1_000 : e.retry_after.to_f
|
111
|
+
sleep timeout
|
112
|
+
_write_raw(key, points)
|
91
113
|
end
|
92
114
|
end
|
93
115
|
end
|
@@ -27,17 +27,36 @@ module InfluxDB2
|
|
27
27
|
|
28
28
|
# Creates write api configuration.
|
29
29
|
#
|
30
|
-
# @param write_type: methods of write (batching, asynchronous, synchronous)
|
31
|
-
# @param batch_size: the number of data point to collect in batch
|
32
|
-
# @param flush_interval: flush data at least in this interval
|
33
30
|
class WriteOptions
|
34
|
-
|
31
|
+
# @param [WriteType] write_type: methods of write (batching, synchronous)
|
32
|
+
# @param [Integer] batch_size: the number of data point to collect in batch
|
33
|
+
# @param [Integer] flush_interval: flush data at least in this interval
|
34
|
+
# @param [Integer] retry_interval: number of milliseconds to retry unsuccessful write.
|
35
|
+
# The retry interval is used when the InfluxDB server does not specify "Retry-After" header.
|
36
|
+
# @param [Integer] jitter_interval: the number of milliseconds to increase the batch flush interval
|
37
|
+
# by a random amount
|
38
|
+
def initialize(write_type: WriteType::SYNCHRONOUS, batch_size: 1_000, flush_interval: 1_000, retry_interval: 1_000,
|
39
|
+
jitter_interval: 0)
|
40
|
+
_check_not_negative('batch_size', batch_size)
|
41
|
+
_check_not_negative('flush_interval', flush_interval)
|
42
|
+
_check_not_negative('retry_interval', retry_interval)
|
43
|
+
_check_positive('jitter_interval', jitter_interval)
|
35
44
|
@write_type = write_type
|
36
45
|
@batch_size = batch_size
|
37
46
|
@flush_interval = flush_interval
|
47
|
+
@retry_interval = retry_interval
|
48
|
+
@jitter_interval = jitter_interval
|
38
49
|
end
|
39
50
|
|
40
|
-
attr_reader :write_type, :batch_size, :flush_interval
|
51
|
+
attr_reader :write_type, :batch_size, :flush_interval, :retry_interval, :jitter_interval
|
52
|
+
|
53
|
+
def _check_not_negative(key, value)
|
54
|
+
raise ArgumentError, "The '#{key}' should be positive or zero, but is: #{value}" if value <= 0
|
55
|
+
end
|
56
|
+
|
57
|
+
def _check_positive(key, value)
|
58
|
+
raise ArgumentError, "The '#{key}' should be positive number, but is: #{value}" if value < 0
|
59
|
+
end
|
41
60
|
end
|
42
61
|
|
43
62
|
SYNCHRONOUS = InfluxDB2::WriteOptions.new(write_type: WriteType::SYNCHRONOUS)
|
@@ -210,9 +229,14 @@ module InfluxDB2
|
|
210
229
|
elsif data.is_a?(Hash)
|
211
230
|
_generate_payload(Point.from_hash(data), bucket: bucket, org: org, precision: precision)
|
212
231
|
elsif data.respond_to? :map
|
213
|
-
data.map do |item|
|
232
|
+
payloads = data.map do |item|
|
214
233
|
_generate_payload(item, bucket: bucket, org: org, precision: precision)
|
215
|
-
end.reject(&:nil?)
|
234
|
+
end.reject(&:nil?)
|
235
|
+
if @write_options.write_type == WriteType::BATCHING
|
236
|
+
payloads
|
237
|
+
else
|
238
|
+
payloads.join("\n".freeze)
|
239
|
+
end
|
216
240
|
end
|
217
241
|
end
|
218
242
|
end
|
@@ -25,7 +25,7 @@ class WriteApiBatchingTest < MiniTest::Test
|
|
25
25
|
WebMock.disable_net_connect!
|
26
26
|
|
27
27
|
@write_options = InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING,
|
28
|
-
batch_size: 2, flush_interval: 5_000)
|
28
|
+
batch_size: 2, flush_interval: 5_000, retry_interval: 2_000)
|
29
29
|
@client = InfluxDB2::Client.new('http://localhost:9999',
|
30
30
|
'my-token',
|
31
31
|
bucket: 'my-bucket',
|
@@ -44,6 +44,29 @@ class WriteApiBatchingTest < MiniTest::Test
|
|
44
44
|
WebMock.reset!
|
45
45
|
end
|
46
46
|
|
47
|
+
def test_batch_configuration
|
48
|
+
error = assert_raises ArgumentError do
|
49
|
+
InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, batch_size: 0)
|
50
|
+
end
|
51
|
+
assert_equal "The 'batch_size' should be positive or zero, but is: 0", error.message
|
52
|
+
|
53
|
+
error = assert_raises ArgumentError do
|
54
|
+
InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, flush_interval: -10)
|
55
|
+
end
|
56
|
+
assert_equal "The 'flush_interval' should be positive or zero, but is: -10", error.message
|
57
|
+
|
58
|
+
error = assert_raises ArgumentError do
|
59
|
+
InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, retry_interval: 0)
|
60
|
+
end
|
61
|
+
assert_equal "The 'retry_interval' should be positive or zero, but is: 0", error.message
|
62
|
+
|
63
|
+
InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, jitter_interval: 0)
|
64
|
+
error = assert_raises ArgumentError do
|
65
|
+
InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, jitter_interval: -10)
|
66
|
+
end
|
67
|
+
assert_equal "The 'jitter_interval' should be positive number, but is: -10", error.message
|
68
|
+
end
|
69
|
+
|
47
70
|
def test_batch_size
|
48
71
|
stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
|
49
72
|
.to_return(status: 204)
|
@@ -163,4 +186,107 @@ class WriteApiBatchingTest < MiniTest::Test
|
|
163
186
|
"h2o_feet,location=coyote_creek level\\ water_level=2.0 2\n" \
|
164
187
|
'h2o_feet,location=coyote_creek level\\ water_level=3.0 3')
|
165
188
|
end
|
189
|
+
|
190
|
+
def test_retry_interval_by_config
|
191
|
+
error_body = '{"code":"temporarily unavailable","message":"Token is temporarily over quota. '\
|
192
|
+
'The Retry-After header describes when to try the write again."}'
|
193
|
+
|
194
|
+
stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
|
195
|
+
.to_return(status: 429, headers: { 'X-Platform-Error-Code' => 'temporarily unavailable' }, body: error_body).then
|
196
|
+
.to_return(status: 204)
|
197
|
+
|
198
|
+
request = "h2o_feet,location=coyote_creek water_level=1.0 1\n" \
|
199
|
+
'h2o_feet,location=coyote_creek water_level=2.0 2'
|
200
|
+
|
201
|
+
@write_client.write(data: ['h2o_feet,location=coyote_creek water_level=1.0 1',
|
202
|
+
'h2o_feet,location=coyote_creek water_level=2.0 2'])
|
203
|
+
|
204
|
+
sleep(0.5)
|
205
|
+
|
206
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
207
|
+
times: 1, body: request)
|
208
|
+
|
209
|
+
sleep(1)
|
210
|
+
|
211
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
212
|
+
times: 1, body: request)
|
213
|
+
|
214
|
+
sleep(1)
|
215
|
+
|
216
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
217
|
+
times: 2, body: request)
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_retry_interval_by_header
|
221
|
+
error_body = '{"code":"temporarily unavailable","message":"Server is temporarily unavailable to accept writes. '\
|
222
|
+
'The Retry-After header describes when to try the write again."}'
|
223
|
+
|
224
|
+
stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
|
225
|
+
.to_return(status: 503, headers: { 'X-Platform-Error-Code' => 'temporarily unavailable', 'Retry-After' => '3' },
|
226
|
+
body: error_body).then
|
227
|
+
.to_return(status: 204)
|
228
|
+
|
229
|
+
request = "h2o_feet,location=coyote_creek water_level=1.0 1\n" \
|
230
|
+
'h2o_feet,location=coyote_creek water_level=2.0 2'
|
231
|
+
|
232
|
+
@write_client.write(data: ['h2o_feet,location=coyote_creek water_level=1.0 1',
|
233
|
+
InfluxDB2::Point.new(name: 'h2o_feet')
|
234
|
+
.add_tag('location', 'coyote_creek')
|
235
|
+
.add_field('water_level', 2.0)
|
236
|
+
.time(2, InfluxDB2::WritePrecision::NANOSECOND)])
|
237
|
+
|
238
|
+
sleep(0.5)
|
239
|
+
|
240
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
241
|
+
times: 1, body: request)
|
242
|
+
|
243
|
+
sleep(1)
|
244
|
+
|
245
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
246
|
+
times: 1, body: request)
|
247
|
+
|
248
|
+
sleep(1)
|
249
|
+
|
250
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
251
|
+
times: 1, body: request)
|
252
|
+
|
253
|
+
sleep(1)
|
254
|
+
|
255
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
256
|
+
times: 2, body: request)
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_jitter_interval
|
260
|
+
@client.close!
|
261
|
+
|
262
|
+
@client = InfluxDB2::Client.new('http://localhost:9999',
|
263
|
+
'my-token',
|
264
|
+
bucket: 'my-bucket',
|
265
|
+
org: 'my-org',
|
266
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
267
|
+
use_ssl: false)
|
268
|
+
|
269
|
+
@write_options = InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING,
|
270
|
+
batch_size: 2, flush_interval: 5_000, jitter_interval: 2_000)
|
271
|
+
@write_client = @client.create_write_api(write_options: @write_options)
|
272
|
+
|
273
|
+
stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
|
274
|
+
.to_return(status: 204)
|
275
|
+
|
276
|
+
request = "h2o_feet,location=coyote_creek water_level=1.0 1\n" \
|
277
|
+
'h2o_feet,location=coyote_creek water_level=2.0 2'
|
278
|
+
|
279
|
+
@write_client.write(data: ['h2o_feet,location=coyote_creek water_level=1.0 1',
|
280
|
+
'h2o_feet,location=coyote_creek water_level=2.0 2'])
|
281
|
+
|
282
|
+
sleep(0.1)
|
283
|
+
|
284
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
285
|
+
times: 0, body: request)
|
286
|
+
|
287
|
+
sleep(2)
|
288
|
+
|
289
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
290
|
+
times: 1, body: request)
|
291
|
+
end
|
166
292
|
end
|
@@ -129,6 +129,25 @@ class WriteApiTest < MiniTest::Test
|
|
129
129
|
times: 1, body: expected)
|
130
130
|
end
|
131
131
|
|
132
|
+
def test_array_of_array
|
133
|
+
stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
|
134
|
+
.to_return(status: 204)
|
135
|
+
client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
|
136
|
+
bucket: 'my-bucket',
|
137
|
+
org: 'my-org',
|
138
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
139
|
+
use_ssl: false)
|
140
|
+
|
141
|
+
client.create_write_api.write(data: ['h2o,location=west value=33i 15', ['h2o,location=west value=34i 16',
|
142
|
+
'h2o,location=west value=35i 17']])
|
143
|
+
|
144
|
+
expected = "h2o,location=west value=33i 15\nh2o,location=west value=34i 16"\
|
145
|
+
"\nh2o,location=west value=35i 17"
|
146
|
+
|
147
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
|
148
|
+
times: 1, body: expected)
|
149
|
+
end
|
150
|
+
|
132
151
|
def test_authorization_header
|
133
152
|
stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
|
134
153
|
.to_return(status: 204)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: influxdb-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.0.pre.
|
4
|
+
version: 1.2.0.pre.562
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakub Bednar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|