nats-pure 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nats/io/client.rb +2 -0
- data/lib/nats/io/js.rb +141 -24
- data/lib/nats/io/kv.rb +181 -23
- data/lib/nats/io/version.rb +1 -1
- 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: f1d8302826b885f0c3a173530bd3d504b5e7a4eb7ec684ac3b43b1ee8f9cf4e3
|
4
|
+
data.tar.gz: 04aa8801b7ddf434155d1ebf40b03fdd6b89bfc6f95d968ff4a501684081ca02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a98b75d47e4b8256c05d284324399807e0bbaf210f2970856b106b46a1264cc12bd96cb00516cb007fd9c68cab001bf08516aee1db46718552bd7397cf8ccb2f
|
7
|
+
data.tar.gz: b752276fa498c423ecdd0002e530639514ef39a1f5c93e73606c6a6f0351cf275817e13c0339d880fadef9e956fdf7b1f63cc816ff0cd2a2e254db73e071344c
|
data/lib/nats/io/client.rb
CHANGED
data/lib/nats/io/js.rb
CHANGED
@@ -19,7 +19,6 @@ require 'time'
|
|
19
19
|
require 'base64'
|
20
20
|
|
21
21
|
module NATS
|
22
|
-
|
23
22
|
# JetStream returns a context with a similar API as the NATS::Client
|
24
23
|
# but with enhanced functions to persist and consume messages from
|
25
24
|
# the NATS JetStream engine.
|
@@ -118,6 +117,7 @@ module NATS
|
|
118
117
|
manual_ack = params[:manual_ack]
|
119
118
|
idle_heartbeat = params[:idle_heartbeat]
|
120
119
|
flow_control = params[:flow_control]
|
120
|
+
config = params[:config]
|
121
121
|
|
122
122
|
if queue
|
123
123
|
if durable and durable != queue
|
@@ -184,7 +184,7 @@ module NATS
|
|
184
184
|
config.flow_control = flow_control
|
185
185
|
if idle_heartbeat or config.idle_heartbeat
|
186
186
|
idle_heartbeat = config.idle_heartbeat if config.idle_heartbeat
|
187
|
-
idle_heartbeat = idle_heartbeat *
|
187
|
+
idle_heartbeat = idle_heartbeat * ::NATS::NANOSECONDS
|
188
188
|
config.idle_heartbeat = idle_heartbeat
|
189
189
|
end
|
190
190
|
|
@@ -222,7 +222,9 @@ module NATS
|
|
222
222
|
# @option params [Hash] :config Configuration for the consumer.
|
223
223
|
# @return [NATS::JetStream::PullSubscription]
|
224
224
|
def pull_subscribe(subject, durable, params={})
|
225
|
-
|
225
|
+
if durable.empty? && !params[:consumer]
|
226
|
+
raise JetStream::Error::InvalidDurableName.new("nats: invalid durable name")
|
227
|
+
end
|
226
228
|
params[:consumer] ||= durable
|
227
229
|
stream = params[:stream].nil? ? find_stream_name_by_subject(subject) : params[:stream]
|
228
230
|
|
@@ -329,7 +331,16 @@ module NATS
|
|
329
331
|
else
|
330
332
|
config
|
331
333
|
end
|
332
|
-
|
334
|
+
|
335
|
+
req_subject = case
|
336
|
+
when config[:name]
|
337
|
+
# NOTE: Only supported after nats-server v2.9.0
|
338
|
+
if config[:filter_subject] && config[:filter_subject] != ">"
|
339
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}.#{config[:filter_subject]}"
|
340
|
+
else
|
341
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}"
|
342
|
+
end
|
343
|
+
when config[:durable_name]
|
333
344
|
"#{@prefix}.CONSUMER.DURABLE.CREATE.#{stream}.#{config[:durable_name]}"
|
334
345
|
else
|
335
346
|
"#{@prefix}.CONSUMER.CREATE.#{stream}"
|
@@ -339,7 +350,11 @@ module NATS
|
|
339
350
|
# Check if have to normalize ack wait so that it is in nanoseconds for Go compat.
|
340
351
|
if config[:ack_wait]
|
341
352
|
raise ArgumentError.new("nats: invalid ack wait") unless config[:ack_wait].is_a?(Integer)
|
342
|
-
config[:ack_wait] = config[:ack_wait] *
|
353
|
+
config[:ack_wait] = config[:ack_wait] * ::NATS::NANOSECONDS
|
354
|
+
end
|
355
|
+
if config[:inactive_threshold]
|
356
|
+
raise ArgumentError.new("nats: invalid inactive threshold") unless config[:inactive_threshold].is_a?(Integer)
|
357
|
+
config[:inactive_threshold] = config[:inactive_threshold] * ::NATS::NANOSECONDS
|
343
358
|
end
|
344
359
|
|
345
360
|
req = {
|
@@ -396,28 +411,96 @@ module NATS
|
|
396
411
|
result[:streams].first
|
397
412
|
end
|
398
413
|
|
399
|
-
|
400
|
-
|
401
|
-
|
414
|
+
# get_msg retrieves a message from the stream.
|
415
|
+
# @param next [Boolean] Fetch the next message for a subject.
|
416
|
+
# @param seq [Integer] Sequence number of a message.
|
417
|
+
# @param subject [String] Subject of the message.
|
418
|
+
# @param direct [Boolean] Use direct mode to for faster access (requires NATS v2.9.0)
|
419
|
+
def get_msg(stream_name, params={})
|
420
|
+
req = {}
|
421
|
+
case
|
422
|
+
when params[:next]
|
423
|
+
req[:seq] = params[:seq]
|
424
|
+
req[:next_by_subj] = params[:subject]
|
425
|
+
when params[:seq]
|
426
|
+
req[:seq] = params[:seq]
|
427
|
+
when params[:subject]
|
428
|
+
req[:last_by_subj] = params[:subject]
|
429
|
+
end
|
430
|
+
|
402
431
|
data = req.to_json
|
403
|
-
|
404
|
-
|
432
|
+
if params[:direct]
|
433
|
+
if params[:subject] and not params[:seq]
|
434
|
+
# last_by_subject type request requires no payload.
|
435
|
+
data = ''
|
436
|
+
req_subject = "#{@prefix}.DIRECT.GET.#{stream_name}.#{params[:subject]}"
|
437
|
+
else
|
438
|
+
req_subject = "#{@prefix}.DIRECT.GET.#{stream_name}"
|
439
|
+
end
|
440
|
+
else
|
441
|
+
req_subject = "#{@prefix}.STREAM.MSG.GET.#{stream_name}"
|
442
|
+
end
|
443
|
+
resp = api_request(req_subject, data, direct: params[:direct])
|
444
|
+
msg = if params[:direct]
|
445
|
+
_lift_msg_to_raw_msg(resp)
|
446
|
+
else
|
447
|
+
JetStream::API::RawStreamMsg.new(resp[:message])
|
448
|
+
end
|
449
|
+
|
450
|
+
msg
|
451
|
+
end
|
452
|
+
|
453
|
+
def get_last_msg(stream_name, subject, params={})
|
454
|
+
params[:subject] = subject
|
455
|
+
get_msg(stream_name, params)
|
456
|
+
end
|
457
|
+
|
458
|
+
def account_info
|
459
|
+
api_request("#{@prefix}.INFO")
|
405
460
|
end
|
406
461
|
|
407
462
|
private
|
408
463
|
|
409
464
|
def api_request(req_subject, req="", params={})
|
410
465
|
params[:timeout] ||= @opts[:timeout]
|
411
|
-
|
412
|
-
|
466
|
+
msg = begin
|
467
|
+
@nc.request(req_subject, req, **params)
|
468
|
+
rescue NATS::IO::NoRespondersError
|
469
|
+
raise JetStream::Error::ServiceUnavailable
|
470
|
+
end
|
471
|
+
|
472
|
+
result = if params[:direct]
|
473
|
+
msg
|
474
|
+
else
|
413
475
|
JSON.parse(msg.data, symbolize_names: true)
|
414
|
-
rescue NATS::IO::NoRespondersError
|
415
|
-
raise JetStream::Error::ServiceUnavailable
|
416
476
|
end
|
417
|
-
|
477
|
+
if result.is_a?(Hash) and result[:error]
|
478
|
+
raise JS.from_error(result[:error])
|
479
|
+
end
|
418
480
|
|
419
481
|
result
|
420
482
|
end
|
483
|
+
|
484
|
+
def _lift_msg_to_raw_msg(msg)
|
485
|
+
if msg.header and msg.header['Status']
|
486
|
+
status = msg.header['Status']
|
487
|
+
if status == '404'
|
488
|
+
raise ::NATS::JetStream::Error::NotFound.new
|
489
|
+
else
|
490
|
+
raise JS.from_msg(msg)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
subject = msg.header['Nats-Subject']
|
494
|
+
seq = msg.header['Nats-Sequence']
|
495
|
+
raw_msg = JetStream::API::RawStreamMsg.new(
|
496
|
+
subject: subject,
|
497
|
+
seq: seq,
|
498
|
+
headers: msg.header,
|
499
|
+
)
|
500
|
+
raw_msg.data = msg.data
|
501
|
+
|
502
|
+
raw_msg
|
503
|
+
end
|
421
504
|
end
|
422
505
|
|
423
506
|
# PushSubscription is included into NATS::Subscription so that it
|
@@ -1106,7 +1189,7 @@ module NATS
|
|
1106
1189
|
opts[:created] = Time.parse(opts[:created])
|
1107
1190
|
opts[:ack_floor] = SequenceInfo.new(opts[:ack_floor])
|
1108
1191
|
opts[:delivered] = SequenceInfo.new(opts[:delivered])
|
1109
|
-
opts[:config][:ack_wait] = opts[:config][:ack_wait] /
|
1192
|
+
opts[:config][:ack_wait] = opts[:config][:ack_wait] / ::NATS::NANOSECONDS
|
1110
1193
|
opts[:config] = ConsumerConfig.new(opts[:config])
|
1111
1194
|
opts.delete(:cluster)
|
1112
1195
|
# Filter unrecognized fields just in case.
|
@@ -1135,12 +1218,24 @@ module NATS
|
|
1135
1218
|
# @return [Integer]
|
1136
1219
|
# @!attribute max_ack_pending
|
1137
1220
|
# @return [Integer]
|
1138
|
-
ConsumerConfig = Struct.new(:
|
1139
|
-
:
|
1140
|
-
:
|
1221
|
+
ConsumerConfig = Struct.new(:name, :durable_name, :description,
|
1222
|
+
:deliver_policy, :opt_start_seq, :opt_start_time,
|
1223
|
+
:ack_policy, :ack_wait, :max_deliver, :backoff,
|
1141
1224
|
:filter_subject, :replay_policy, :rate_limit_bps,
|
1142
1225
|
:sample_freq, :max_waiting, :max_ack_pending,
|
1143
1226
|
:flow_control, :idle_heartbeat, :headers_only,
|
1227
|
+
|
1228
|
+
# Pull based options
|
1229
|
+
:max_batch, :max_expires,
|
1230
|
+
# Push based consumers
|
1231
|
+
:deliver_subject, :deliver_group,
|
1232
|
+
# Ephemeral inactivity threshold
|
1233
|
+
:inactive_threshold,
|
1234
|
+
# Generally inherited by parent stream and other markers,
|
1235
|
+
# now can be configured directly.
|
1236
|
+
:num_replicas,
|
1237
|
+
# Force memory storage
|
1238
|
+
:mem_storage,
|
1144
1239
|
keyword_init: true) do
|
1145
1240
|
def initialize(opts={})
|
1146
1241
|
# Filter unrecognized fields just in case.
|
@@ -1194,10 +1289,32 @@ module NATS
|
|
1194
1289
|
# @return [Integer]
|
1195
1290
|
# @!attribute duplicate_window
|
1196
1291
|
# @return [Integer]
|
1197
|
-
StreamConfig = Struct.new(
|
1198
|
-
:
|
1199
|
-
:
|
1200
|
-
:
|
1292
|
+
StreamConfig = Struct.new(
|
1293
|
+
:name,
|
1294
|
+
:description,
|
1295
|
+
:subjects,
|
1296
|
+
:retention,
|
1297
|
+
:max_consumers,
|
1298
|
+
:max_msgs,
|
1299
|
+
:max_bytes,
|
1300
|
+
:discard,
|
1301
|
+
:max_age,
|
1302
|
+
:max_msgs_per_subject,
|
1303
|
+
:max_msg_size,
|
1304
|
+
:storage,
|
1305
|
+
:num_replicas,
|
1306
|
+
:no_ack,
|
1307
|
+
:duplicate_window,
|
1308
|
+
:placement,
|
1309
|
+
:mirror,
|
1310
|
+
:sources,
|
1311
|
+
:sealed,
|
1312
|
+
:deny_delete,
|
1313
|
+
:deny_purge,
|
1314
|
+
:allow_rollup_hdrs,
|
1315
|
+
:republish,
|
1316
|
+
:allow_direct,
|
1317
|
+
:mirror_direct,
|
1201
1318
|
keyword_init: true) do
|
1202
1319
|
def initialize(opts={})
|
1203
1320
|
# Filter unrecognized fields just in case.
|
@@ -1230,7 +1347,7 @@ module NATS
|
|
1230
1347
|
def initialize(opts={})
|
1231
1348
|
opts[:config] = StreamConfig.new(opts[:config])
|
1232
1349
|
opts[:state] = StreamState.new(opts[:state])
|
1233
|
-
opts[:created] = Time.parse(opts[:created])
|
1350
|
+
opts[:created] = ::Time.parse(opts[:created])
|
1234
1351
|
|
1235
1352
|
# Filter fields and freeze.
|
1236
1353
|
rem = opts.keys - members
|
data/lib/nats/io/kv.rb
CHANGED
@@ -20,46 +20,181 @@ module NATS
|
|
20
20
|
KV_PURGE = "PURGE"
|
21
21
|
MSG_ROLLUP_SUBJECT = "sub"
|
22
22
|
MSG_ROLLUP_ALL = "all"
|
23
|
+
ROLLUP = "Nats-Rollup"
|
23
24
|
|
24
25
|
def initialize(opts={})
|
25
26
|
@name = opts[:name]
|
26
27
|
@stream = opts[:stream]
|
27
28
|
@pre = opts[:pre]
|
28
29
|
@js = opts[:js]
|
30
|
+
@direct = opts[:direct]
|
31
|
+
end
|
32
|
+
|
33
|
+
class Error < NATS::Error; end
|
34
|
+
|
35
|
+
# When a key is not found.
|
36
|
+
class KeyNotFoundError < Error
|
37
|
+
attr_reader :entry, :op
|
38
|
+
def initialize(params={})
|
39
|
+
@entry = params[:entry]
|
40
|
+
@op = params[:op]
|
41
|
+
@message = params[:message]
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
msg = "nats: key not found"
|
46
|
+
msg = "#{msg}: #{@message}" if @message
|
47
|
+
msg
|
48
|
+
end
|
29
49
|
end
|
30
50
|
|
31
51
|
# When a key is not found because it was deleted.
|
32
|
-
class KeyDeletedError <
|
52
|
+
class KeyDeletedError < KeyNotFoundError
|
53
|
+
def to_s
|
54
|
+
"nats: key was deleted"
|
55
|
+
end
|
56
|
+
end
|
33
57
|
|
34
58
|
# When there was no bucket present.
|
35
|
-
class BucketNotFoundError <
|
59
|
+
class BucketNotFoundError < Error; end
|
36
60
|
|
37
61
|
# When it is an invalid bucket.
|
38
|
-
class BadBucketError <
|
62
|
+
class BadBucketError < Error; end
|
63
|
+
|
64
|
+
# When the result is an unexpected sequence.
|
65
|
+
class KeyWrongLastSequenceError < Error
|
66
|
+
def initialize(msg)
|
67
|
+
@msg = msg
|
68
|
+
end
|
69
|
+
def to_s
|
70
|
+
"nats: #{@msg}"
|
71
|
+
end
|
72
|
+
end
|
39
73
|
|
40
74
|
# get returns the latest value for the key.
|
41
|
-
def get(key)
|
42
|
-
|
75
|
+
def get(key, params={})
|
76
|
+
entry = nil
|
77
|
+
begin
|
78
|
+
entry = _get(key, params)
|
79
|
+
rescue KeyDeletedError
|
80
|
+
raise KeyNotFoundError
|
81
|
+
end
|
82
|
+
|
83
|
+
entry
|
84
|
+
end
|
85
|
+
|
86
|
+
def _get(key, params={})
|
87
|
+
msg = nil
|
88
|
+
subject = "#{@pre}#{key}"
|
89
|
+
|
90
|
+
if params[:revision]
|
91
|
+
msg = @js.get_msg(@stream,
|
92
|
+
seq: params[:revision],
|
93
|
+
direct: @direct)
|
94
|
+
else
|
95
|
+
msg = @js.get_msg(@stream,
|
96
|
+
subject: subject,
|
97
|
+
seq: params[:revision],
|
98
|
+
direct: @direct)
|
99
|
+
end
|
100
|
+
|
43
101
|
entry = Entry.new(bucket: @name, key: key, value: msg.data, revision: msg.seq)
|
44
102
|
|
103
|
+
if subject != msg.subject
|
104
|
+
raise KeyNotFoundError.new(
|
105
|
+
entry: entry,
|
106
|
+
message: "expected '#{subject}', but got '#{msg.subject}'"
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
45
110
|
if not msg.headers.nil?
|
46
111
|
op = msg.headers[KV_OP]
|
47
|
-
|
112
|
+
if op == KV_DEL or op == KV_PURGE
|
113
|
+
raise KeyDeletedError.new(entry: entry, op: op)
|
114
|
+
end
|
48
115
|
end
|
49
116
|
|
50
117
|
entry
|
118
|
+
rescue NATS::JetStream::Error::NotFound
|
119
|
+
raise KeyNotFoundError
|
51
120
|
end
|
121
|
+
private :_get
|
52
122
|
|
53
123
|
# put will place the new value for the key into the store
|
54
124
|
# and return the revision number.
|
55
125
|
def put(key, value)
|
56
|
-
@js.publish("#{@pre}#{key}", value)
|
126
|
+
ack = @js.publish("#{@pre}#{key}", value)
|
127
|
+
ack.seq
|
128
|
+
end
|
129
|
+
|
130
|
+
# create will add the key/value pair iff it does not exist.
|
131
|
+
def create(key, value)
|
132
|
+
pa = nil
|
133
|
+
begin
|
134
|
+
pa = update(key, value, last: 0)
|
135
|
+
rescue KeyWrongLastSequenceError => err
|
136
|
+
# In case of attempting to recreate an already deleted key,
|
137
|
+
# the client would get a KeyWrongLastSequenceError. When this happens,
|
138
|
+
# it is needed to fetch latest revision number and attempt to update.
|
139
|
+
begin
|
140
|
+
# NOTE: This reimplements the following behavior from Go client.
|
141
|
+
#
|
142
|
+
# Since we have tombstones for DEL ops for watchers, this could be from that
|
143
|
+
# so we need to double check.
|
144
|
+
#
|
145
|
+
_get(key)
|
146
|
+
|
147
|
+
# No exception so not a deleted key, so reraise the original KeyWrongLastSequenceError.
|
148
|
+
# If it was deleted then the error exception will contain metadata
|
149
|
+
# to recreate using the last revision.
|
150
|
+
raise err
|
151
|
+
rescue KeyDeletedError => err
|
152
|
+
pa = update(key, value, last: err.entry.revision)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
pa
|
157
|
+
end
|
158
|
+
|
159
|
+
EXPECTED_LAST_SUBJECT_SEQUENCE = "Nats-Expected-Last-Subject-Sequence"
|
160
|
+
|
161
|
+
# update will update the value iff the latest revision matches.
|
162
|
+
def update(key, value, params={})
|
163
|
+
hdrs = {}
|
164
|
+
last = (params[:last] ||= 0)
|
165
|
+
hdrs[EXPECTED_LAST_SUBJECT_SEQUENCE] = last.to_s
|
166
|
+
ack = nil
|
167
|
+
begin
|
168
|
+
ack = @js.publish("#{@pre}#{key}", value, header: hdrs)
|
169
|
+
rescue NATS::JetStream::Error::APIError => err
|
170
|
+
if err.err_code == 10071
|
171
|
+
raise KeyWrongLastSequenceError.new(err.description)
|
172
|
+
else
|
173
|
+
raise err
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
ack.seq
|
57
178
|
end
|
58
179
|
|
59
180
|
# delete will place a delete marker and remove all previous revisions.
|
60
|
-
def delete(key)
|
181
|
+
def delete(key, params={})
|
61
182
|
hdrs = {}
|
62
183
|
hdrs[KV_OP] = KV_DEL
|
184
|
+
last = (params[:last] ||= 0)
|
185
|
+
if last > 0
|
186
|
+
hdrs[EXPECTED_LAST_SUBJECT_SEQUENCE] = last.to_s
|
187
|
+
end
|
188
|
+
ack = @js.publish("#{@pre}#{key}", header: hdrs)
|
189
|
+
|
190
|
+
ack.seq
|
191
|
+
end
|
192
|
+
|
193
|
+
# purge will remove the key and all revisions.
|
194
|
+
def purge(key)
|
195
|
+
hdrs = {}
|
196
|
+
hdrs[KV_OP] = KV_PURGE
|
197
|
+
hdrs[ROLLUP] = MSG_ROLLUP_SUBJECT
|
63
198
|
@js.publish("#{@pre}#{key}", header: hdrs)
|
64
199
|
end
|
65
200
|
|
@@ -69,7 +204,7 @@ module NATS
|
|
69
204
|
BucketStatus.new(info, @name)
|
70
205
|
end
|
71
206
|
|
72
|
-
Entry = Struct.new(:bucket, :key, :value, :revision, keyword_init: true) do
|
207
|
+
Entry = Struct.new(:bucket, :key, :value, :revision, :delta, :created, :operation, keyword_init: true) do
|
73
208
|
def initialize(opts={})
|
74
209
|
rem = opts.keys - members
|
75
210
|
opts.delete_if { |k| rem.include?(k) }
|
@@ -94,14 +229,24 @@ module NATS
|
|
94
229
|
end
|
95
230
|
|
96
231
|
def ttl
|
97
|
-
@nfo.config.max_age /
|
232
|
+
@nfo.config.max_age / ::NATS::NANOSECONDS
|
98
233
|
end
|
99
234
|
end
|
100
|
-
|
101
|
-
module API
|
102
|
-
KeyValueConfig = Struct.new(
|
103
|
-
|
104
|
-
|
235
|
+
|
236
|
+
module API
|
237
|
+
KeyValueConfig = Struct.new(
|
238
|
+
:bucket,
|
239
|
+
:description,
|
240
|
+
:max_value_size,
|
241
|
+
:history,
|
242
|
+
:ttl,
|
243
|
+
:max_bytes,
|
244
|
+
:storage,
|
245
|
+
:replicas,
|
246
|
+
:placement,
|
247
|
+
:republish,
|
248
|
+
:direct,
|
249
|
+
keyword_init: true) do
|
105
250
|
def initialize(opts={})
|
106
251
|
rem = opts.keys - members
|
107
252
|
opts.delete_if { |k| rem.include?(k) }
|
@@ -127,40 +272,53 @@ module NATS
|
|
127
272
|
stream: stream,
|
128
273
|
pre: "$KV.#{bucket}.",
|
129
274
|
js: self,
|
275
|
+
direct: si.config.allow_direct
|
130
276
|
)
|
131
277
|
end
|
132
278
|
|
133
279
|
def create_key_value(config)
|
134
|
-
config = if not config.is_a?(
|
280
|
+
config = if not config.is_a?(KeyValue::API::KeyValueConfig)
|
135
281
|
KeyValue::API::KeyValueConfig.new(config)
|
136
282
|
else
|
137
283
|
config
|
138
284
|
end
|
139
285
|
config.history ||= 1
|
140
286
|
config.replicas ||= 1
|
287
|
+
duplicate_window = 2 * 60 # 2 minutes
|
141
288
|
if config.ttl
|
142
|
-
|
289
|
+
if config.ttl < duplicate_window
|
290
|
+
duplicate_window = config.ttl
|
291
|
+
end
|
292
|
+
config.ttl = config.ttl * ::NATS::NANOSECONDS
|
143
293
|
end
|
144
294
|
|
145
295
|
stream = JetStream::API::StreamConfig.new(
|
146
296
|
name: "KV_#{config.bucket}",
|
297
|
+
description: config.description,
|
147
298
|
subjects: ["$KV.#{config.bucket}.>"],
|
148
|
-
|
149
|
-
|
299
|
+
allow_direct: config.direct,
|
300
|
+
allow_rollup_hdrs: true,
|
301
|
+
deny_delete: true,
|
302
|
+
discard: "new",
|
303
|
+
duplicate_window: duplicate_window * ::NATS::NANOSECONDS,
|
150
304
|
max_age: config.ttl,
|
305
|
+
max_bytes: config.max_bytes,
|
306
|
+
max_consumers: -1,
|
151
307
|
max_msg_size: config.max_value_size,
|
152
|
-
|
308
|
+
max_msgs: -1,
|
309
|
+
max_msgs_per_subject: config.history,
|
153
310
|
num_replicas: config.replicas,
|
154
|
-
|
155
|
-
|
311
|
+
storage: config.storage,
|
312
|
+
republish: config.republish,
|
156
313
|
)
|
157
|
-
resp = add_stream(stream)
|
158
314
|
|
315
|
+
si = add_stream(stream)
|
159
316
|
KeyValue.new(
|
160
317
|
name: config.bucket,
|
161
318
|
stream: stream.name,
|
162
319
|
pre: "$KV.#{config.bucket}.",
|
163
320
|
js: self,
|
321
|
+
direct: si.config.allow_direct
|
164
322
|
)
|
165
323
|
end
|
166
324
|
|
data/lib/nats/io/version.rb
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
module NATS
|
16
16
|
module IO
|
17
17
|
# VERSION is the version of the client announced on CONNECT to the server.
|
18
|
-
VERSION = "2.
|
18
|
+
VERSION = "2.2.0".freeze
|
19
19
|
|
20
20
|
# LANG is the lang runtime of the client announced on CONNECT to the server.
|
21
21
|
LANG = "#{RUBY_ENGINE}#{RUBY_VERSION}".freeze
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nats-pure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Waldemar Quevedo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-01 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: NATS is an open-source, high-performance, lightweight cloud messaging
|
14
14
|
system.
|