nats-pure 2.3.0 → 2.5.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/CHANGELOG.md +3 -0
- data/README.md +10 -3
- data/lib/nats/client.rb +7 -2
- data/lib/nats/io/client.rb +304 -282
- data/lib/nats/io/errors.rb +2 -0
- data/lib/nats/io/jetstream/api.rb +54 -47
- data/lib/nats/io/jetstream/errors.rb +30 -14
- data/lib/nats/io/jetstream/js/config.rb +9 -3
- data/lib/nats/io/jetstream/js/header.rb +15 -9
- data/lib/nats/io/jetstream/js/status.rb +11 -5
- data/lib/nats/io/jetstream/js/sub.rb +4 -2
- data/lib/nats/io/jetstream/js.rb +10 -8
- data/lib/nats/io/jetstream/manager.rb +104 -83
- data/lib/nats/io/jetstream/msg/ack.rb +15 -9
- data/lib/nats/io/jetstream/msg/ack_methods.rb +24 -22
- data/lib/nats/io/jetstream/msg/metadata.rb +9 -7
- data/lib/nats/io/jetstream/msg.rb +11 -4
- data/lib/nats/io/jetstream/pull_subscription.rb +21 -10
- data/lib/nats/io/jetstream/push_subscription.rb +3 -1
- data/lib/nats/io/jetstream.rb +125 -54
- data/lib/nats/io/kv/api.rb +7 -3
- data/lib/nats/io/kv/bucket_status.rb +7 -5
- data/lib/nats/io/kv/errors.rb +25 -2
- data/lib/nats/io/kv/manager.rb +19 -10
- data/lib/nats/io/kv.rb +359 -22
- data/lib/nats/io/msg.rb +19 -19
- data/lib/nats/io/parser.rb +23 -23
- data/lib/nats/io/rails.rb +2 -0
- data/lib/nats/io/subscription.rb +25 -22
- data/lib/nats/io/version.rb +4 -2
- data/lib/nats/io/websocket.rb +10 -8
- data/lib/nats/nuid.rb +33 -22
- data/lib/nats/service/callbacks.rb +22 -0
- data/lib/nats/service/endpoint.rb +155 -0
- data/lib/nats/service/errors.rb +44 -0
- data/lib/nats/service/group.rb +37 -0
- data/lib/nats/service/monitoring.rb +108 -0
- data/lib/nats/service/stats.rb +52 -0
- data/lib/nats/service/status.rb +66 -0
- data/lib/nats/service/validator.rb +31 -0
- data/lib/nats/service.rb +121 -0
- data/lib/nats/utils/list.rb +26 -0
- data/lib/nats-pure.rb +5 -0
- data/lib/nats.rb +10 -6
- metadata +176 -5
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2021 The NATS Authors
|
2
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
5
|
# you may not use this file except in compliance with the License.
|
@@ -31,15 +33,15 @@ module NATS
|
|
31
33
|
# @param params [Hash] Options to customize API request.
|
32
34
|
# @option params [Float] :timeout Time to wait for response.
|
33
35
|
# @return [JetStream::API::StreamCreateResponse] The result of creating a Stream.
|
34
|
-
def add_stream(config, params={})
|
35
|
-
config = if
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
def add_stream(config, params = {})
|
37
|
+
config = if !config.is_a?(JetStream::API::StreamConfig)
|
38
|
+
JetStream::API::StreamConfig.new(config)
|
39
|
+
else
|
40
|
+
config
|
41
|
+
end
|
40
42
|
stream = config[:name]
|
41
43
|
raise ArgumentError.new(":name is required to create streams") unless stream
|
42
|
-
raise ArgumentError.new("Spaces, tabs, period (.), greater than (>) or asterisk (*) are prohibited in stream names") if stream =~ /(\s
|
44
|
+
raise ArgumentError.new("Spaces, tabs, period (.), greater than (>) or asterisk (*) are prohibited in stream names") if stream =~ /(\s|\.|>|\*)/
|
43
45
|
req_subject = "#{@prefix}.STREAM.CREATE.#{stream}"
|
44
46
|
|
45
47
|
cfg = config.to_h.compact
|
@@ -52,11 +54,11 @@ module NATS
|
|
52
54
|
# @param params [Hash] Options to customize API request.
|
53
55
|
# @option params [Float] :timeout Time to wait for response.
|
54
56
|
# @return [JetStream::API::StreamInfo] The latest StreamInfo of the stream.
|
55
|
-
def stream_info(stream, params={})
|
56
|
-
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil?
|
57
|
+
def stream_info(stream, params = {})
|
58
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
57
59
|
|
58
60
|
req_subject = "#{@prefix}.STREAM.INFO.#{stream}"
|
59
|
-
result = api_request(req_subject,
|
61
|
+
result = api_request(req_subject, "", params)
|
60
62
|
JetStream::API::StreamInfo.new(result)
|
61
63
|
end
|
62
64
|
|
@@ -65,15 +67,15 @@ module NATS
|
|
65
67
|
# @param params [Hash] Options to customize API request.
|
66
68
|
# @option params [Float] :timeout Time to wait for response.
|
67
69
|
# @return [JetStream::API::StreamCreateResponse] The result of creating a Stream.
|
68
|
-
def update_stream(config, params={})
|
69
|
-
config = if
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
def update_stream(config, params = {})
|
71
|
+
config = if !config.is_a?(JetStream::API::StreamConfig)
|
72
|
+
JetStream::API::StreamConfig.new(config)
|
73
|
+
else
|
74
|
+
config
|
75
|
+
end
|
74
76
|
stream = config[:name]
|
75
77
|
raise ArgumentError.new(":name is required to create streams") unless stream
|
76
|
-
raise ArgumentError.new("Spaces, tabs, period (.), greater than (>) or asterisk (*) are prohibited in stream names") if stream =~ /(\s
|
78
|
+
raise ArgumentError.new("Spaces, tabs, period (.), greater than (>) or asterisk (*) are prohibited in stream names") if stream =~ /(\s|\.|>|\*)/
|
77
79
|
req_subject = "#{@prefix}.STREAM.UPDATE.#{stream}"
|
78
80
|
cfg = config.to_h.compact
|
79
81
|
result = api_request(req_subject, cfg.to_json, params)
|
@@ -85,11 +87,11 @@ module NATS
|
|
85
87
|
# @param params [Hash] Options to customize API request.
|
86
88
|
# @option params [Float] :timeout Time to wait for response.
|
87
89
|
# @return [Boolean]
|
88
|
-
def delete_stream(stream, params={})
|
89
|
-
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil?
|
90
|
+
def delete_stream(stream, params = {})
|
91
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
90
92
|
|
91
93
|
req_subject = "#{@prefix}.STREAM.DELETE.#{stream}"
|
92
|
-
result = api_request(req_subject,
|
94
|
+
result = api_request(req_subject, "", params)
|
93
95
|
result[:success]
|
94
96
|
end
|
95
97
|
|
@@ -99,27 +101,45 @@ module NATS
|
|
99
101
|
# @param params [Hash] Options to customize API request.
|
100
102
|
# @option params [Float] :timeout Time to wait for response.
|
101
103
|
# @return [JetStream::API::ConsumerInfo] The result of creating a Consumer.
|
102
|
-
def add_consumer(stream, config, params={})
|
103
|
-
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil?
|
104
|
-
config = if
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
req_subject =
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
104
|
+
def add_consumer(stream, config, params = {})
|
105
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
106
|
+
config = if !config.is_a?(JetStream::API::ConsumerConfig)
|
107
|
+
JetStream::API::ConsumerConfig.new(config)
|
108
|
+
else
|
109
|
+
config
|
110
|
+
end
|
111
|
+
config[:name] ||= config[:durable_name]
|
112
|
+
req_subject = if config[:name]
|
113
|
+
###############################################################################
|
114
|
+
# #
|
115
|
+
# Using names is the supported way of creating consumers (NATS +v2.9.0. #
|
116
|
+
# #
|
117
|
+
###############################################################################
|
118
|
+
if config[:filter_subject] && config[:filter_subject] != ">"
|
119
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}.#{config[:filter_subject]}"
|
120
|
+
else
|
121
|
+
##############################################################################
|
122
|
+
# #
|
123
|
+
# Endpoint to support creating ANY consumer with multi-filters (NATS +v2.10) #
|
124
|
+
# #
|
125
|
+
##############################################################################
|
126
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}"
|
127
|
+
end
|
128
|
+
elsif config[:durable_name]
|
129
|
+
###############################################################################
|
130
|
+
# #
|
131
|
+
# Endpoint to support creating DURABLES before NATS v2.9.0. #
|
132
|
+
# #
|
133
|
+
###############################################################################
|
134
|
+
"#{@prefix}.CONSUMER.DURABLE.CREATE.#{stream}.#{config[:durable_name]}"
|
135
|
+
else
|
136
|
+
###############################################################################
|
137
|
+
# #
|
138
|
+
# Endpoint to support creating EPHEMERALS before NATS v2.9.0. #
|
139
|
+
# #
|
140
|
+
###############################################################################
|
141
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}"
|
142
|
+
end
|
123
143
|
|
124
144
|
config[:ack_policy] ||= JS::Config::AckExplicit
|
125
145
|
# Check if have to normalize ack wait so that it is in nanoseconds for Go compat.
|
@@ -131,6 +151,10 @@ module NATS
|
|
131
151
|
raise ArgumentError.new("nats: invalid inactive threshold") unless config[:inactive_threshold].is_a?(Integer)
|
132
152
|
config[:inactive_threshold] = config[:inactive_threshold] * ::NATS::NANOSECONDS
|
133
153
|
end
|
154
|
+
if config[:idle_heartbeat]
|
155
|
+
raise ArgumentError.new("nats: invalid idle heartbeat") unless config[:idle_heartbeat].is_a?(Integer)
|
156
|
+
config[:idle_heartbeat] = config[:idle_heartbeat] * ::NATS::NANOSECONDS
|
157
|
+
end
|
134
158
|
|
135
159
|
cfg = config.to_h.compact
|
136
160
|
req = {
|
@@ -148,12 +172,12 @@ module NATS
|
|
148
172
|
# @param params [Hash] Options to customize API request.
|
149
173
|
# @option params [Float] :timeout Time to wait for response.
|
150
174
|
# @return [JetStream::API::ConsumerInfo] The latest ConsumerInfo of the consumer.
|
151
|
-
def consumer_info(stream, consumer, params={})
|
152
|
-
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil?
|
153
|
-
raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil?
|
175
|
+
def consumer_info(stream, consumer, params = {})
|
176
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
177
|
+
raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil? || consumer.empty?
|
154
178
|
|
155
179
|
req_subject = "#{@prefix}.CONSUMER.INFO.#{stream}.#{consumer}"
|
156
|
-
result = api_request(req_subject,
|
180
|
+
result = api_request(req_subject, "", params)
|
157
181
|
JetStream::API::ConsumerInfo.new(result)
|
158
182
|
end
|
159
183
|
|
@@ -163,12 +187,12 @@ module NATS
|
|
163
187
|
# @param params [Hash] Options to customize API request.
|
164
188
|
# @option params [Float] :timeout Time to wait for response.
|
165
189
|
# @return [Boolean]
|
166
|
-
def delete_consumer(stream, consumer, params={})
|
167
|
-
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil?
|
168
|
-
raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil?
|
190
|
+
def delete_consumer(stream, consumer, params = {})
|
191
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
192
|
+
raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil? || consumer.empty?
|
169
193
|
|
170
194
|
req_subject = "#{@prefix}.CONSUMER.DELETE.#{stream}.#{consumer}"
|
171
|
-
result = api_request(req_subject,
|
195
|
+
result = api_request(req_subject, "", params)
|
172
196
|
result[:success]
|
173
197
|
end
|
174
198
|
|
@@ -178,9 +202,9 @@ module NATS
|
|
178
202
|
# @param params [Hash] Options to customize API request.
|
179
203
|
# @option params [Float] :timeout Time to wait for response.
|
180
204
|
# @return [String] The name of the JetStream stream for the subject.
|
181
|
-
def find_stream_name_by_subject(subject, params={})
|
205
|
+
def find_stream_name_by_subject(subject, params = {})
|
182
206
|
req_subject = "#{@prefix}.STREAM.NAMES"
|
183
|
-
req = {
|
207
|
+
req = {subject: subject}
|
184
208
|
result = api_request(req_subject, req.to_json, params)
|
185
209
|
raise JetStream::Error::NotFound unless result[:streams]
|
186
210
|
|
@@ -194,23 +218,22 @@ module NATS
|
|
194
218
|
# @option seq [Integer] Sequence number of a message.
|
195
219
|
# @option subject [String] Subject of the message.
|
196
220
|
# @option direct [Boolean] Use direct mode to for faster access (requires NATS v2.9.0)
|
197
|
-
def get_msg(stream_name, params={})
|
221
|
+
def get_msg(stream_name, params = {})
|
198
222
|
req = {}
|
199
|
-
|
200
|
-
when params[:next]
|
223
|
+
if params[:next]
|
201
224
|
req[:seq] = params[:seq]
|
202
225
|
req[:next_by_subj] = params[:subject]
|
203
|
-
|
226
|
+
elsif params[:seq]
|
204
227
|
req[:seq] = params[:seq]
|
205
|
-
|
228
|
+
elsif params[:subject]
|
206
229
|
req[:last_by_subj] = params[:subject]
|
207
230
|
end
|
208
231
|
|
209
232
|
data = req.to_json
|
210
233
|
if params[:direct]
|
211
|
-
if params[:subject]
|
234
|
+
if params[:subject] && !(params[:seq])
|
212
235
|
# last_by_subject type request requires no payload.
|
213
|
-
data =
|
236
|
+
data = ""
|
214
237
|
req_subject = "#{@prefix}.DIRECT.GET.#{stream_name}.#{params[:subject]}"
|
215
238
|
else
|
216
239
|
req_subject = "#{@prefix}.DIRECT.GET.#{stream_name}"
|
@@ -219,16 +242,14 @@ module NATS
|
|
219
242
|
req_subject = "#{@prefix}.STREAM.MSG.GET.#{stream_name}"
|
220
243
|
end
|
221
244
|
resp = api_request(req_subject, data, direct: params[:direct])
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
msg
|
245
|
+
if params[:direct]
|
246
|
+
_lift_msg_to_raw_msg(resp)
|
247
|
+
else
|
248
|
+
JetStream::API::RawStreamMsg.new(resp[:message])
|
249
|
+
end
|
229
250
|
end
|
230
251
|
|
231
|
-
def get_last_msg(stream_name, subject, params={})
|
252
|
+
def get_last_msg(stream_name, subject, params = {})
|
232
253
|
params[:subject] = subject
|
233
254
|
get_msg(stream_name, params)
|
234
255
|
end
|
@@ -239,20 +260,20 @@ module NATS
|
|
239
260
|
|
240
261
|
private
|
241
262
|
|
242
|
-
def api_request(req_subject, req="", params={})
|
263
|
+
def api_request(req_subject, req = "", params = {})
|
243
264
|
params[:timeout] ||= @opts[:timeout]
|
244
265
|
msg = begin
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
266
|
+
@nc.request(req_subject, req, **params)
|
267
|
+
rescue NATS::IO::NoRespondersError
|
268
|
+
raise JetStream::Error::ServiceUnavailable
|
269
|
+
end
|
249
270
|
|
250
271
|
result = if params[:direct]
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
if result.is_a?(Hash)
|
272
|
+
msg
|
273
|
+
else
|
274
|
+
JSON.parse(msg.data, symbolize_names: true)
|
275
|
+
end
|
276
|
+
if result.is_a?(Hash) && result[:error]
|
256
277
|
raise JS.from_error(result[:error])
|
257
278
|
end
|
258
279
|
|
@@ -260,21 +281,21 @@ module NATS
|
|
260
281
|
end
|
261
282
|
|
262
283
|
def _lift_msg_to_raw_msg(msg)
|
263
|
-
if msg.header
|
264
|
-
status = msg.header[
|
265
|
-
if status ==
|
284
|
+
if msg.header && msg.header["Status"]
|
285
|
+
status = msg.header["Status"]
|
286
|
+
if status == "404"
|
266
287
|
raise ::NATS::JetStream::Error::NotFound.new
|
267
288
|
else
|
268
289
|
raise JS.from_msg(msg)
|
269
290
|
end
|
270
291
|
end
|
271
|
-
subject = msg.header[
|
272
|
-
seq = msg.header[
|
292
|
+
subject = msg.header["Nats-Subject"]
|
293
|
+
seq = msg.header["Nats-Sequence"]
|
273
294
|
raw_msg = JetStream::API::RawStreamMsg.new(
|
274
295
|
subject: subject,
|
275
296
|
seq: seq,
|
276
|
-
headers: msg.header
|
277
|
-
|
297
|
+
headers: msg.header
|
298
|
+
)
|
278
299
|
raw_msg.data = msg.data
|
279
300
|
|
280
301
|
raw_msg
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2021 The NATS Authors
|
2
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
5
|
# you may not use this file except in compliance with the License.
|
@@ -16,19 +18,21 @@ module NATS
|
|
16
18
|
class JetStream
|
17
19
|
module Msg
|
18
20
|
module Ack
|
21
|
+
# rubocop:disable Naming/ConstantName
|
22
|
+
|
19
23
|
# Ack types
|
20
|
-
Ack
|
21
|
-
Nak
|
22
|
-
Progress =
|
23
|
-
Term
|
24
|
+
Ack = "+ACK"
|
25
|
+
Nak = "-NAK"
|
26
|
+
Progress = "+WPI"
|
27
|
+
Term = "+TERM"
|
24
28
|
|
25
|
-
Empty =
|
26
|
-
DotSep =
|
27
|
-
NoDomainName =
|
29
|
+
Empty = ""
|
30
|
+
DotSep = "."
|
31
|
+
NoDomainName = "_"
|
28
32
|
|
29
33
|
# Position
|
30
|
-
Prefix0 =
|
31
|
-
Prefix1 =
|
34
|
+
Prefix0 = "$JS"
|
35
|
+
Prefix1 = "ACK"
|
32
36
|
Domain = 2
|
33
37
|
AccHash = 3
|
34
38
|
Stream = 4
|
@@ -50,6 +54,8 @@ module NATS
|
|
50
54
|
V2TokenCounts = 12
|
51
55
|
|
52
56
|
SequencePair = Struct.new(:stream, :consumer)
|
57
|
+
|
58
|
+
# rubocop:enable Naming/ConstantName
|
53
59
|
end
|
54
60
|
private_constant :Ack
|
55
61
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2021 The NATS Authors
|
2
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
5
|
# you may not use this file except in compliance with the License.
|
@@ -20,10 +22,10 @@ module NATS
|
|
20
22
|
ensure_is_acked_once!
|
21
23
|
|
22
24
|
resp = if params[:timeout]
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
@nc.request(@reply, Ack::Ack, **params)
|
26
|
+
else
|
27
|
+
@nc.publish(@reply, Ack::Ack)
|
28
|
+
end
|
27
29
|
@sub.synchronize { @ackd = true }
|
28
30
|
|
29
31
|
resp
|
@@ -42,15 +44,15 @@ module NATS
|
|
42
44
|
def nak(**params)
|
43
45
|
ensure_is_acked_once!
|
44
46
|
payload = if params[:delay]
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
"#{Ack::Nak} #{{delay: params[:delay]}.to_json}"
|
48
|
+
else
|
49
|
+
Ack::Nak
|
50
|
+
end
|
49
51
|
resp = if params[:timeout]
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
@nc.request(@reply, payload, **params)
|
53
|
+
else
|
54
|
+
@nc.publish(@reply, payload)
|
55
|
+
end
|
54
56
|
@sub.synchronize { @ackd = true }
|
55
57
|
|
56
58
|
resp
|
@@ -60,10 +62,10 @@ module NATS
|
|
60
62
|
ensure_is_acked_once!
|
61
63
|
|
62
64
|
resp = if params[:timeout]
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
@nc.request(@reply, Ack::Term, **params)
|
66
|
+
else
|
67
|
+
@nc.publish(@reply, Ack::Term)
|
68
|
+
end
|
67
69
|
@sub.synchronize { @ackd = true }
|
68
70
|
|
69
71
|
resp
|
@@ -74,7 +76,7 @@ module NATS
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def metadata
|
77
|
-
@meta ||= parse_metadata(reply)
|
79
|
+
@meta ||= parse_metadata(@reply)
|
78
80
|
end
|
79
81
|
|
80
82
|
private
|
@@ -88,18 +90,18 @@ module NATS
|
|
88
90
|
end
|
89
91
|
|
90
92
|
def parse_metadata(reply)
|
93
|
+
return unless reply && !reply.empty?
|
91
94
|
tokens = reply.split(Ack::DotSep)
|
92
95
|
n = tokens.count
|
93
96
|
|
94
|
-
|
95
|
-
when n < Ack::V1TokenCounts || (n > Ack::V1TokenCounts and n < Ack::V2TokenCounts)
|
97
|
+
if n < Ack::V1TokenCounts || ((n > Ack::V1TokenCounts) && (n < Ack::V2TokenCounts))
|
96
98
|
raise NotJSMessage.new("nats: not a jetstream message")
|
97
|
-
|
99
|
+
elsif tokens[0] != Ack::Prefix0 || tokens[1] != Ack::Prefix1
|
98
100
|
raise NotJSMessage.new("nats: not a jetstream message")
|
99
|
-
|
101
|
+
elsif n == Ack::V1TokenCounts
|
100
102
|
tokens.insert(Ack::Domain, Ack::Empty)
|
101
103
|
tokens.insert(Ack::AccHash, Ack::Empty)
|
102
|
-
|
104
|
+
elsif tokens[Ack::Domain] == Ack::NoDomainName
|
103
105
|
tokens[Ack::Domain] = Ack::Empty
|
104
106
|
end
|
105
107
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2021 The NATS Authors
|
2
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
5
|
# you may not use this file except in compliance with the License.
|
@@ -12,7 +14,7 @@
|
|
12
14
|
# limitations under the License.
|
13
15
|
#
|
14
16
|
|
15
|
-
require
|
17
|
+
require "time"
|
16
18
|
|
17
19
|
module NATS
|
18
20
|
class JetStream
|
@@ -21,13 +23,13 @@ module NATS
|
|
21
23
|
attr_reader :sequence, :num_delivered, :num_pending, :timestamp, :stream, :consumer, :domain
|
22
24
|
|
23
25
|
def initialize(opts)
|
24
|
-
@sequence
|
25
|
-
@domain
|
26
|
+
@sequence = Ack::SequencePair.new(opts[Ack::StreamSeq].to_i, opts[Ack::ConsumerSeq].to_i)
|
27
|
+
@domain = opts[Ack::Domain]
|
26
28
|
@num_delivered = opts[Ack::NumDelivered].to_i
|
27
|
-
@num_pending
|
28
|
-
@timestamp
|
29
|
-
@stream
|
30
|
-
@consumer
|
29
|
+
@num_pending = opts[Ack::NumPending].to_i
|
30
|
+
@timestamp = Time.at((opts[Ack::Timestamp].to_i / 1_000_000_000.0))
|
31
|
+
@stream = opts[Ack::Stream]
|
32
|
+
@consumer = opts[Ack::Consumer]
|
31
33
|
# TODO: Not exposed in Go client either right now.
|
32
34
|
# account = opts[Ack::AccHash]
|
33
35
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2021 The NATS Authors
|
2
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
5
|
# you may not use this file except in compliance with the License.
|
@@ -12,9 +14,9 @@
|
|
12
14
|
# limitations under the License.
|
13
15
|
#
|
14
16
|
|
15
|
-
require_relative
|
16
|
-
require_relative
|
17
|
-
require_relative
|
17
|
+
require_relative "msg/ack"
|
18
|
+
require_relative "msg/ack_methods"
|
19
|
+
require_relative "msg/metadata"
|
18
20
|
|
19
21
|
module NATS
|
20
22
|
class JetStream
|
@@ -23,4 +25,9 @@ module NATS
|
|
23
25
|
module Msg
|
24
26
|
end
|
25
27
|
end
|
26
|
-
|
28
|
+
|
29
|
+
class Msg
|
30
|
+
# Enhance it with ack related methods from JetStream to ack msgs.
|
31
|
+
include JetStream::Msg::AckMethods
|
32
|
+
end
|
33
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2021 The NATS Authors
|
2
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
5
|
# you may not use this file except in compliance with the License.
|
@@ -12,7 +14,7 @@
|
|
12
14
|
# limitations under the License.
|
13
15
|
#
|
14
16
|
|
15
|
-
require_relative
|
17
|
+
require_relative "errors"
|
16
18
|
|
17
19
|
module NATS
|
18
20
|
class JetStream
|
@@ -39,7 +41,7 @@ module NATS
|
|
39
41
|
module PullSubscription
|
40
42
|
# next_msg is not available for pull based subscriptions.
|
41
43
|
# @raise [NATS::JetStream::Error]
|
42
|
-
def next_msg(params={})
|
44
|
+
def next_msg(params = {})
|
43
45
|
raise ::NATS::JetStream::Error.new("nats: pull subscription cannot use next_msg")
|
44
46
|
end
|
45
47
|
|
@@ -49,7 +51,7 @@ module NATS
|
|
49
51
|
# @param params [Hash] Options to customize the fetch request.
|
50
52
|
# @option params [Float] :timeout Duration of the fetch request before it expires.
|
51
53
|
# @return [Array<NATS::Msg>]
|
52
|
-
def fetch(batch=1, params={})
|
54
|
+
def fetch(batch = 1, params = {})
|
53
55
|
if batch < 1
|
54
56
|
raise ::NATS::JetStream::Error.new("nats: invalid batch size")
|
55
57
|
end
|
@@ -80,7 +82,7 @@ module NATS
|
|
80
82
|
if JS.is_status_msg(msg)
|
81
83
|
case msg.header["Status"]
|
82
84
|
when JS::Status::NoMsgs
|
83
|
-
|
85
|
+
nil
|
84
86
|
when JS::Status::RequestTimeout
|
85
87
|
# Skip
|
86
88
|
else
|
@@ -193,27 +195,31 @@ module NATS
|
|
193
195
|
|
194
196
|
# Check if have not received yet a single message.
|
195
197
|
duration = MonotonicTime.since(start_time)
|
196
|
-
|
198
|
+
|
199
|
+
if msgs.empty? && (duration > timeout)
|
197
200
|
raise NATS::Timeout.new("nats: fetch timeout")
|
198
201
|
end
|
199
202
|
|
200
203
|
needed = batch - msgs.count
|
201
|
-
while needed > 0
|
204
|
+
while (needed > 0) && (MonotonicTime.since(start_time) < timeout)
|
202
205
|
duration = MonotonicTime.since(start_time)
|
203
206
|
|
204
207
|
# Wait for the rest of the messages.
|
205
208
|
synchronize do
|
206
|
-
|
207
209
|
# Wait until there is a message delivered.
|
208
210
|
if @pending_queue.empty?
|
209
211
|
deadline = timeout - duration
|
212
|
+
MonotonicTime.now
|
213
|
+
|
210
214
|
wait_for_msgs_cond.wait(deadline) if deadline > 0
|
211
215
|
|
212
216
|
duration = MonotonicTime.since(start_time)
|
213
|
-
if msgs.empty? && @pending_queue.empty?
|
217
|
+
if msgs.empty? && @pending_queue.empty? && (duration > timeout)
|
214
218
|
raise NATS::Timeout.new("nats: fetch timeout")
|
215
219
|
end
|
216
|
-
|
220
|
+
end
|
221
|
+
|
222
|
+
unless @pending_queue.empty?
|
217
223
|
msg = @pending_queue.pop
|
218
224
|
@pending_size -= msg.data.size
|
219
225
|
|
@@ -244,6 +250,11 @@ module NATS
|
|
244
250
|
end
|
245
251
|
end
|
246
252
|
|
253
|
+
# Check if timed out waiting for messages.
|
254
|
+
if msgs.empty? && (MonotonicTime.since(start_time) > timeout)
|
255
|
+
raise NATS::Timeout.new("nats: fetch timeout")
|
256
|
+
end
|
257
|
+
|
247
258
|
msgs
|
248
259
|
end
|
249
260
|
|
@@ -251,7 +262,7 @@ module NATS
|
|
251
262
|
# @param params [Hash] Options to customize API request.
|
252
263
|
# @option params [Float] :timeout Time to wait for response.
|
253
264
|
# @return [JetStream::API::ConsumerInfo] The latest ConsumerInfo of the consumer.
|
254
|
-
def consumer_info(params={})
|
265
|
+
def consumer_info(params = {})
|
255
266
|
@jsi.js.consumer_info(@jsi.stream, @jsi.consumer, params)
|
256
267
|
end
|
257
268
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2021 The NATS Authors
|
2
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
3
5
|
# you may not use this file except in compliance with the License.
|
@@ -33,7 +35,7 @@ module NATS
|
|
33
35
|
# @param params [Hash] Options to customize API request.
|
34
36
|
# @option params [Float] :timeout Time to wait for response.
|
35
37
|
# @return [JetStream::API::ConsumerInfo] The latest ConsumerInfo of the consumer.
|
36
|
-
def consumer_info(params={})
|
38
|
+
def consumer_info(params = {})
|
37
39
|
@jsi.js.consumer_info(@jsi.stream, @jsi.consumer, params)
|
38
40
|
end
|
39
41
|
end
|