nats-pure 2.1.0 → 2.2.0
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/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.
|