nats-pure 2.4.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/README.md +10 -3
  4. data/lib/nats/client.rb +7 -3
  5. data/lib/nats/io/client.rb +303 -280
  6. data/lib/nats/io/errors.rb +2 -0
  7. data/lib/nats/io/jetstream/api.rb +53 -50
  8. data/lib/nats/io/jetstream/errors.rb +30 -14
  9. data/lib/nats/io/jetstream/js/config.rb +9 -3
  10. data/lib/nats/io/jetstream/js/header.rb +15 -9
  11. data/lib/nats/io/jetstream/js/status.rb +11 -5
  12. data/lib/nats/io/jetstream/js/sub.rb +4 -2
  13. data/lib/nats/io/jetstream/js.rb +10 -8
  14. data/lib/nats/io/jetstream/manager.rb +103 -101
  15. data/lib/nats/io/jetstream/msg/ack.rb +15 -9
  16. data/lib/nats/io/jetstream/msg/ack_methods.rb +24 -22
  17. data/lib/nats/io/jetstream/msg/metadata.rb +9 -7
  18. data/lib/nats/io/jetstream/msg.rb +11 -4
  19. data/lib/nats/io/jetstream/pull_subscription.rb +21 -10
  20. data/lib/nats/io/jetstream/push_subscription.rb +3 -1
  21. data/lib/nats/io/jetstream.rb +102 -106
  22. data/lib/nats/io/kv/api.rb +7 -3
  23. data/lib/nats/io/kv/bucket_status.rb +7 -5
  24. data/lib/nats/io/kv/errors.rb +25 -2
  25. data/lib/nats/io/kv/manager.rb +19 -10
  26. data/lib/nats/io/kv.rb +359 -22
  27. data/lib/nats/io/msg.rb +19 -19
  28. data/lib/nats/io/parser.rb +23 -23
  29. data/lib/nats/io/rails.rb +2 -0
  30. data/lib/nats/io/subscription.rb +25 -22
  31. data/lib/nats/io/version.rb +4 -2
  32. data/lib/nats/io/websocket.rb +10 -8
  33. data/lib/nats/nuid.rb +33 -22
  34. data/lib/nats/service/callbacks.rb +22 -0
  35. data/lib/nats/service/endpoint.rb +155 -0
  36. data/lib/nats/service/errors.rb +44 -0
  37. data/lib/nats/service/group.rb +37 -0
  38. data/lib/nats/service/monitoring.rb +108 -0
  39. data/lib/nats/service/stats.rb +52 -0
  40. data/lib/nats/service/status.rb +66 -0
  41. data/lib/nats/service/validator.rb +31 -0
  42. data/lib/nats/service.rb +121 -0
  43. data/lib/nats/utils/list.rb +26 -0
  44. data/lib/nats-pure.rb +5 -0
  45. data/lib/nats.rb +10 -6
  46. 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 not config.is_a?(JetStream::API::StreamConfig)
36
- JetStream::API::StreamConfig.new(config)
37
- else
38
- config
39
- end
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? or stream.empty?
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, '', params)
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 not config.is_a?(JetStream::API::StreamConfig)
70
- JetStream::API::StreamConfig.new(config)
71
- else
72
- config
73
- end
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? or stream.empty?
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, '', params)
94
+ result = api_request(req_subject, "", params)
93
95
  result[:success]
94
96
  end
95
97
 
@@ -99,46 +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? or stream.empty?
104
- config = if not config.is_a?(JetStream::API::ConsumerConfig)
105
- JetStream::API::ConsumerConfig.new(config)
106
- else
107
- config
108
- end
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
109
111
  config[:name] ||= config[:durable_name]
110
- req_subject = case
111
- when config[:name]
112
- ###############################################################################
113
- # #
114
- # Using names is the supported way of creating consumers (NATS +v2.9.0. #
115
- # #
116
- ###############################################################################
117
- if config[:filter_subject] && config[:filter_subject] != ">"
118
- "#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}.#{config[:filter_subject]}"
119
- else
120
- ##############################################################################
121
- # #
122
- # Endpoint to support creating ANY consumer with multi-filters (NATS +v2.10) #
123
- # #
124
- ##############################################################################
125
- "#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}"
126
- end
127
- when config[:durable_name]
128
- ###############################################################################
129
- # #
130
- # Endpoint to support creating DURABLES before NATS v2.9.0. #
131
- # #
132
- ###############################################################################
133
- "#{@prefix}.CONSUMER.DURABLE.CREATE.#{stream}.#{config[:durable_name]}"
134
- else
135
- ###############################################################################
136
- # #
137
- # Endpoint to support creating EPHEMERALS before NATS v2.9.0. #
138
- # #
139
- ###############################################################################
140
- "#{@prefix}.CONSUMER.CREATE.#{stream}"
141
- end
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
142
143
 
143
144
  config[:ack_policy] ||= JS::Config::AckExplicit
144
145
  # Check if have to normalize ack wait so that it is in nanoseconds for Go compat.
@@ -150,6 +151,10 @@ module NATS
150
151
  raise ArgumentError.new("nats: invalid inactive threshold") unless config[:inactive_threshold].is_a?(Integer)
151
152
  config[:inactive_threshold] = config[:inactive_threshold] * ::NATS::NANOSECONDS
152
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
153
158
 
154
159
  cfg = config.to_h.compact
155
160
  req = {
@@ -167,12 +172,12 @@ module NATS
167
172
  # @param params [Hash] Options to customize API request.
168
173
  # @option params [Float] :timeout Time to wait for response.
169
174
  # @return [JetStream::API::ConsumerInfo] The latest ConsumerInfo of the consumer.
170
- def consumer_info(stream, consumer, params={})
171
- raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? or stream.empty?
172
- raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil? or consumer.empty?
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?
173
178
 
174
179
  req_subject = "#{@prefix}.CONSUMER.INFO.#{stream}.#{consumer}"
175
- result = api_request(req_subject, '', params)
180
+ result = api_request(req_subject, "", params)
176
181
  JetStream::API::ConsumerInfo.new(result)
177
182
  end
178
183
 
@@ -182,12 +187,12 @@ module NATS
182
187
  # @param params [Hash] Options to customize API request.
183
188
  # @option params [Float] :timeout Time to wait for response.
184
189
  # @return [Boolean]
185
- def delete_consumer(stream, consumer, params={})
186
- raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? or stream.empty?
187
- raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil? or consumer.empty?
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?
188
193
 
189
194
  req_subject = "#{@prefix}.CONSUMER.DELETE.#{stream}.#{consumer}"
190
- result = api_request(req_subject, '', params)
195
+ result = api_request(req_subject, "", params)
191
196
  result[:success]
192
197
  end
193
198
 
@@ -197,9 +202,9 @@ module NATS
197
202
  # @param params [Hash] Options to customize API request.
198
203
  # @option params [Float] :timeout Time to wait for response.
199
204
  # @return [String] The name of the JetStream stream for the subject.
200
- def find_stream_name_by_subject(subject, params={})
205
+ def find_stream_name_by_subject(subject, params = {})
201
206
  req_subject = "#{@prefix}.STREAM.NAMES"
202
- req = { subject: subject }
207
+ req = {subject: subject}
203
208
  result = api_request(req_subject, req.to_json, params)
204
209
  raise JetStream::Error::NotFound unless result[:streams]
205
210
 
@@ -213,23 +218,22 @@ module NATS
213
218
  # @option seq [Integer] Sequence number of a message.
214
219
  # @option subject [String] Subject of the message.
215
220
  # @option direct [Boolean] Use direct mode to for faster access (requires NATS v2.9.0)
216
- def get_msg(stream_name, params={})
221
+ def get_msg(stream_name, params = {})
217
222
  req = {}
218
- case
219
- when params[:next]
223
+ if params[:next]
220
224
  req[:seq] = params[:seq]
221
225
  req[:next_by_subj] = params[:subject]
222
- when params[:seq]
226
+ elsif params[:seq]
223
227
  req[:seq] = params[:seq]
224
- when params[:subject]
228
+ elsif params[:subject]
225
229
  req[:last_by_subj] = params[:subject]
226
230
  end
227
231
 
228
232
  data = req.to_json
229
233
  if params[:direct]
230
- if params[:subject] and not params[:seq]
234
+ if params[:subject] && !(params[:seq])
231
235
  # last_by_subject type request requires no payload.
232
- data = ''
236
+ data = ""
233
237
  req_subject = "#{@prefix}.DIRECT.GET.#{stream_name}.#{params[:subject]}"
234
238
  else
235
239
  req_subject = "#{@prefix}.DIRECT.GET.#{stream_name}"
@@ -238,16 +242,14 @@ module NATS
238
242
  req_subject = "#{@prefix}.STREAM.MSG.GET.#{stream_name}"
239
243
  end
240
244
  resp = api_request(req_subject, data, direct: params[:direct])
241
- msg = if params[:direct]
242
- _lift_msg_to_raw_msg(resp)
243
- else
244
- JetStream::API::RawStreamMsg.new(resp[:message])
245
- end
246
-
247
- msg
245
+ if params[:direct]
246
+ _lift_msg_to_raw_msg(resp)
247
+ else
248
+ JetStream::API::RawStreamMsg.new(resp[:message])
249
+ end
248
250
  end
249
251
 
250
- def get_last_msg(stream_name, subject, params={})
252
+ def get_last_msg(stream_name, subject, params = {})
251
253
  params[:subject] = subject
252
254
  get_msg(stream_name, params)
253
255
  end
@@ -258,20 +260,20 @@ module NATS
258
260
 
259
261
  private
260
262
 
261
- def api_request(req_subject, req="", params={})
263
+ def api_request(req_subject, req = "", params = {})
262
264
  params[:timeout] ||= @opts[:timeout]
263
265
  msg = begin
264
- @nc.request(req_subject, req, **params)
265
- rescue NATS::IO::NoRespondersError
266
- raise JetStream::Error::ServiceUnavailable
267
- end
266
+ @nc.request(req_subject, req, **params)
267
+ rescue NATS::IO::NoRespondersError
268
+ raise JetStream::Error::ServiceUnavailable
269
+ end
268
270
 
269
271
  result = if params[:direct]
270
- msg
271
- else
272
- JSON.parse(msg.data, symbolize_names: true)
273
- end
274
- if result.is_a?(Hash) and result[:error]
272
+ msg
273
+ else
274
+ JSON.parse(msg.data, symbolize_names: true)
275
+ end
276
+ if result.is_a?(Hash) && result[:error]
275
277
  raise JS.from_error(result[:error])
276
278
  end
277
279
 
@@ -279,21 +281,21 @@ module NATS
279
281
  end
280
282
 
281
283
  def _lift_msg_to_raw_msg(msg)
282
- if msg.header and msg.header['Status']
283
- status = msg.header['Status']
284
- if status == '404'
284
+ if msg.header && msg.header["Status"]
285
+ status = msg.header["Status"]
286
+ if status == "404"
285
287
  raise ::NATS::JetStream::Error::NotFound.new
286
288
  else
287
289
  raise JS.from_msg(msg)
288
290
  end
289
291
  end
290
- subject = msg.header['Nats-Subject']
291
- seq = msg.header['Nats-Sequence']
292
+ subject = msg.header["Nats-Subject"]
293
+ seq = msg.header["Nats-Sequence"]
292
294
  raw_msg = JetStream::API::RawStreamMsg.new(
293
295
  subject: subject,
294
296
  seq: seq,
295
- headers: msg.header,
296
- )
297
+ headers: msg.header
298
+ )
297
299
  raw_msg.data = msg.data
298
300
 
299
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 = ("+ACK".freeze)
21
- Nak = ("-NAK".freeze)
22
- Progress = ("+WPI".freeze)
23
- Term = ("+TERM".freeze)
24
+ Ack = "+ACK"
25
+ Nak = "-NAK"
26
+ Progress = "+WPI"
27
+ Term = "+TERM"
24
28
 
25
- Empty = (''.freeze)
26
- DotSep = ('.'.freeze)
27
- NoDomainName = ('_'.freeze)
29
+ Empty = ""
30
+ DotSep = "."
31
+ NoDomainName = "_"
28
32
 
29
33
  # Position
30
- Prefix0 = ('$JS'.freeze)
31
- Prefix1 = ('ACK'.freeze)
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
- @nc.request(@reply, Ack::Ack, **params)
24
- else
25
- @nc.publish(@reply, Ack::Ack)
26
- end
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
- payload = "#{Ack::Nak} #{{ delay: params[:delay] }.to_json}"
46
- else
47
- Ack::Nak
48
- end
47
+ "#{Ack::Nak} #{{delay: params[:delay]}.to_json}"
48
+ else
49
+ Ack::Nak
50
+ end
49
51
  resp = if params[:timeout]
50
- @nc.request(@reply, payload, **params)
51
- else
52
- @nc.publish(@reply, payload)
53
- end
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
- @nc.request(@reply, Ack::Term, **params)
64
- else
65
- @nc.publish(@reply, Ack::Term)
66
- end
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
- case
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
- when tokens[0] != Ack::Prefix0 || tokens[1] != Ack::Prefix1
99
+ elsif tokens[0] != Ack::Prefix0 || tokens[1] != Ack::Prefix1
98
100
  raise NotJSMessage.new("nats: not a jetstream message")
99
- when n == Ack::V1TokenCounts
101
+ elsif n == Ack::V1TokenCounts
100
102
  tokens.insert(Ack::Domain, Ack::Empty)
101
103
  tokens.insert(Ack::AccHash, Ack::Empty)
102
- when tokens[Ack::Domain] == Ack::NoDomainName
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 'time'
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 = Ack::SequencePair.new(opts[Ack::StreamSeq].to_i, opts[Ack::ConsumerSeq].to_i)
25
- @domain = opts[Ack::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 = opts[Ack::NumPending].to_i
28
- @timestamp = Time.at((opts[Ack::Timestamp].to_i / 1_000_000_000.0))
29
- @stream = opts[Ack::Stream]
30
- @consumer = opts[Ack::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 'msg/ack'
16
- require_relative 'msg/ack_methods'
17
- require_relative 'msg/metadata'
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
- end
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 'errors'
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
- msg = nil
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
- if msgs.empty? and duration > timeout
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 and MonotonicTime.since(start_time) < timeout
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? and duration > timeout
217
+ if msgs.empty? && @pending_queue.empty? && (duration > timeout)
214
218
  raise NATS::Timeout.new("nats: fetch timeout")
215
219
  end
216
- else
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