nats-pure 2.3.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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 -2
  5. data/lib/nats/io/client.rb +304 -282
  6. data/lib/nats/io/errors.rb +2 -0
  7. data/lib/nats/io/jetstream/api.rb +54 -47
  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 +104 -83
  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 +125 -54
  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.
@@ -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 'errors'
16
- require 'base64'
17
- require 'time'
17
+ require_relative "errors"
18
+ require "base64"
19
+ require "time"
18
20
 
19
21
  module NATS
20
22
  class JetStream
@@ -29,12 +31,12 @@ module NATS
29
31
  # @!attribute stream_seq
30
32
  # @return [Integer] The stream sequence.
31
33
  SequenceInfo = Struct.new(:consumer_seq, :stream_seq, :last_active,
32
- keyword_init: true) do
33
- def initialize(opts={})
34
+ keyword_init: true) do
35
+ def initialize(opts = {})
34
36
  # Filter unrecognized fields and freeze.
35
37
  rem = opts.keys - members
36
38
  opts.delete_if { |k| rem.include?(k) }
37
- super(opts)
39
+ super
38
40
  freeze
39
41
  end
40
42
  end
@@ -64,21 +66,23 @@ module NATS
64
66
  # @!attribute cluster
65
67
  # @return [Hash]
66
68
  ConsumerInfo = Struct.new(:type, :stream_name, :name, :created,
67
- :config, :delivered, :ack_floor,
68
- :num_ack_pending, :num_redelivered, :num_waiting,
69
- :num_pending, :cluster, :push_bound,
70
- keyword_init: true) do
71
- def initialize(opts={})
69
+ :config, :delivered, :ack_floor,
70
+ :num_ack_pending, :num_redelivered, :num_waiting,
71
+ :num_pending, :cluster, :push_bound,
72
+ keyword_init: true) do
73
+ def initialize(opts = {})
72
74
  opts[:created] = Time.parse(opts[:created])
73
75
  opts[:ack_floor] = SequenceInfo.new(opts[:ack_floor])
74
76
  opts[:delivered] = SequenceInfo.new(opts[:delivered])
75
77
  opts[:config][:ack_wait] = opts[:config][:ack_wait] / ::NATS::NANOSECONDS
78
+ opts[:config][:inactive_threshold] = opts[:config][:inactive_threshold] / ::NATS::NANOSECONDS if opts[:config][:inactive_threshold]
79
+ opts[:config][:idle_heartbeat] = opts[:config][:idle_heartbeat] / ::NATS::NANOSECONDS if opts[:config][:idle_heartbeat]
76
80
  opts[:config] = ConsumerConfig.new(opts[:config])
77
81
  opts.delete(:cluster)
78
82
  # Filter unrecognized fields just in case.
79
83
  rem = opts.keys - members
80
84
  opts.delete_if { |k| rem.include?(k) }
81
- super(opts)
85
+ super
82
86
  freeze
83
87
  end
84
88
  end
@@ -102,29 +106,30 @@ module NATS
102
106
  # @!attribute max_ack_pending
103
107
  # @return [Integer]
104
108
  ConsumerConfig = Struct.new(:name, :durable_name, :description,
105
- :deliver_policy, :opt_start_seq, :opt_start_time,
106
- :ack_policy, :ack_wait, :max_deliver, :backoff,
107
- :filter_subject, :replay_policy, :rate_limit_bps,
108
- :sample_freq, :max_waiting, :max_ack_pending,
109
- :flow_control, :idle_heartbeat, :headers_only,
110
-
111
- # Pull based options
112
- :max_batch, :max_expires,
113
- # Push based consumers
114
- :deliver_subject, :deliver_group,
115
- # Ephemeral inactivity threshold
116
- :inactive_threshold,
117
- # Generally inherited by parent stream and other markers,
118
- # now can be configured directly.
119
- :num_replicas,
120
- # Force memory storage
121
- :mem_storage,
122
- keyword_init: true) do
123
- def initialize(opts={})
109
+ :deliver_policy, :opt_start_seq, :opt_start_time,
110
+ :ack_policy, :ack_wait, :max_deliver, :backoff,
111
+ :filter_subject, :replay_policy, :rate_limit_bps,
112
+ :sample_freq, :max_waiting, :max_ack_pending,
113
+ :flow_control, :idle_heartbeat, :headers_only,
114
+ # Pull based options
115
+ :max_batch, :max_expires,
116
+ # Push based consumers
117
+ :deliver_subject, :deliver_group,
118
+ # Ephemeral inactivity threshold
119
+ :inactive_threshold,
120
+ # Generally inherited by parent stream and other markers,
121
+ # now can be configured directly.
122
+ :num_replicas,
123
+ # Force memory storage
124
+ :mem_storage,
125
+ # NATS v2.10 features
126
+ :metadata, :filter_subjects, :max_bytes,
127
+ keyword_init: true) do
128
+ def initialize(opts = {})
124
129
  # Filter unrecognized fields just in case.
125
130
  rem = opts.keys - members
126
131
  opts.delete_if { |k| rem.include?(k) }
127
- super(opts)
132
+ super
128
133
  end
129
134
  end
130
135
 
@@ -192,12 +197,14 @@ module NATS
192
197
  :republish,
193
198
  :allow_direct,
194
199
  :mirror_direct,
195
- keyword_init: true) do
196
- def initialize(opts={})
200
+ :metadata,
201
+ keyword_init: true
202
+ ) do
203
+ def initialize(opts = {})
197
204
  # Filter unrecognized fields just in case.
198
205
  rem = opts.keys - members
199
206
  opts.delete_if { |k| rem.include?(k) }
200
- super(opts)
207
+ super
201
208
  end
202
209
  end
203
210
 
@@ -214,8 +221,8 @@ module NATS
214
221
  # @!attribute domain
215
222
  # @return [String]
216
223
  StreamInfo = Struct.new(:type, :config, :created, :state, :domain,
217
- keyword_init: true) do
218
- def initialize(opts={})
224
+ keyword_init: true) do
225
+ def initialize(opts = {})
219
226
  opts[:config] = StreamConfig.new(opts[:config])
220
227
  opts[:state] = StreamState.new(opts[:state])
221
228
  opts[:created] = ::Time.parse(opts[:created])
@@ -223,7 +230,7 @@ module NATS
223
230
  # Filter fields and freeze.
224
231
  rem = opts.keys - members
225
232
  opts.delete_if { |k| rem.include?(k) }
226
- super(opts)
233
+ super
227
234
  freeze
228
235
  end
229
236
  end
@@ -241,12 +248,12 @@ module NATS
241
248
  # @!attribute consumer_count
242
249
  # @return [Integer]
243
250
  StreamState = Struct.new(:messages, :bytes, :first_seq, :first_ts,
244
- :last_seq, :last_ts, :consumer_count,
245
- keyword_init: true) do
246
- def initialize(opts={})
251
+ :last_seq, :last_ts, :consumer_count,
252
+ keyword_init: true) do
253
+ def initialize(opts = {})
247
254
  rem = opts.keys - members
248
255
  opts.delete_if { |k| rem.include?(k) }
249
- super(opts)
256
+ super
250
257
  end
251
258
  end
252
259
 
@@ -263,13 +270,13 @@ module NATS
263
270
  # @!attribute did_create
264
271
  # @return [Boolean]
265
272
  StreamCreateResponse = Struct.new(:type, :config, :created, :state, :did_create,
266
- keyword_init: true) do
267
- def initialize(opts={})
273
+ keyword_init: true) do
274
+ def initialize(opts = {})
268
275
  rem = opts.keys - members
269
276
  opts.delete_if { |k| rem.include?(k) }
270
277
  opts[:config] = StreamConfig.new(opts[:config])
271
278
  opts[:state] = StreamState.new(opts[:state])
272
- super(opts)
279
+ super
273
280
  freeze
274
281
  end
275
282
  end
@@ -293,11 +300,11 @@ module NATS
293
300
  # Filter out members not present.
294
301
  rem = opts.keys - members
295
302
  opts.delete_if { |k| rem.include?(k) }
296
- super(opts)
303
+ super
297
304
  end
298
305
 
299
306
  def sequence
300
- self.seq
307
+ seq
301
308
  end
302
309
  end
303
310
  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.
@@ -16,7 +18,6 @@ module NATS
16
18
  class JetStream
17
19
  # Error is any error that may arise when interacting with JetStream.
18
20
  class Error < NATS::IO::Error
19
-
20
21
  # When there is a NATS::IO::NoResponders error after making a publish request.
21
22
  class NoStreamResponse < Error; end
22
23
 
@@ -41,18 +42,25 @@ module NATS
41
42
 
42
43
  # When the server responds with an error from the JetStream API.
43
44
  class APIError < Error
44
- attr_reader :code, :err_code, :description, :stream, :seq
45
+ attr_accessor :code, :err_code, :description, :stream, :consumer, :seq
45
46
 
46
- def initialize(params={})
47
+ def initialize(params = {})
47
48
  @code = params[:code]
48
49
  @err_code = params[:err_code]
49
50
  @description = params[:description]
50
51
  @stream = params[:stream]
52
+ @consumer = params[:consumer]
51
53
  @seq = params[:seq]
52
54
  end
53
55
 
54
56
  def to_s
55
- "#{@description} (status_code=#{@code}, err_code=#{@err_code})"
57
+ if @stream && @consumer
58
+ "#{@description} (status_code=#{@code}, err_code=#{@err_code}, stream=#{@stream}, consumer=#{@consumer})"
59
+ elsif @stream
60
+ "#{@description} (status_code=#{@code}, err_code=#{@err_code}, stream=#{@stream})"
61
+ else
62
+ "#{@description} (status_code=#{@code}, err_code=#{@err_code})"
63
+ end
56
64
  end
57
65
  end
58
66
 
@@ -61,8 +69,8 @@ module NATS
61
69
  # running in cluster mode.
62
70
  # This condition is represented with a message that has 503 status code header.
63
71
  class ServiceUnavailable < APIError
64
- def initialize(params={})
65
- super(params)
72
+ def initialize(params = {})
73
+ super
66
74
  @code ||= 503
67
75
  end
68
76
  end
@@ -70,8 +78,8 @@ module NATS
70
78
  # When there is a hard failure in the JetStream.
71
79
  # This condition is represented with a message that has 500 status code header.
72
80
  class ServerError < APIError
73
- def initialize(params={})
74
- super(params)
81
+ def initialize(params = {})
82
+ super
75
83
  @code ||= 500
76
84
  end
77
85
  end
@@ -79,23 +87,31 @@ module NATS
79
87
  # When a JetStream object was not found.
80
88
  # This condition is represented with a message that has 404 status code header.
81
89
  class NotFound < APIError
82
- def initialize(params={})
83
- super(params)
90
+ def initialize(params = {})
91
+ super
84
92
  @code ||= 404
85
93
  end
86
94
  end
87
95
 
88
96
  # When the stream is not found.
89
- class StreamNotFound < NotFound; end
97
+ class StreamNotFound < NotFound
98
+ def initialize(params = {})
99
+ super
100
+ end
101
+ end
90
102
 
91
103
  # When the consumer or durable is not found by name.
92
- class ConsumerNotFound < NotFound; end
104
+ class ConsumerNotFound < NotFound
105
+ def initialize(params = {})
106
+ super
107
+ end
108
+ end
93
109
 
94
110
  # When the JetStream client makes an invalid request.
95
111
  # This condition is represented with a message that has 400 status code header.
96
112
  class BadRequest < APIError
97
- def initialize(params={})
98
- super(params)
113
+ def initialize(params = {})
114
+ super
99
115
  @code ||= 400
100
116
  end
101
117
  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.
@@ -16,10 +18,14 @@ module NATS
16
18
  class JetStream
17
19
  module JS
18
20
  module Config
21
+ # rubocop:disable Naming/ConstantName
22
+
19
23
  # AckPolicy
20
- AckExplicit = ("explicit".freeze)
21
- AckAll = ("all".freeze)
22
- AckNone = ("none".freeze)
24
+ AckExplicit = "explicit"
25
+ AckAll = "all"
26
+ AckNone = "none"
27
+
28
+ # rubocop:enable Naming/ConstantName
23
29
  end
24
30
  end
25
31
  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.
@@ -16,15 +18,19 @@ module NATS
16
18
  class JetStream
17
19
  module JS
18
20
  module Header
19
- Status = ("Status".freeze)
20
- Desc = ("Description".freeze)
21
- MsgID = ("Nats-Msg-Id".freeze)
22
- ExpectedStream = ("Nats-Expected-Stream".freeze)
23
- ExpectedLastSeq = ("Nats-Expected-Last-Sequence".freeze)
24
- ExpectedLastSubjSeq = ("Nats-Expected-Last-Subject-Sequence".freeze)
25
- ExpectedLastMsgID = ("Nats-Expected-Last-Msg-Id".freeze)
26
- LastConsumerSeq = ("Nats-Last-Consumer".freeze)
27
- LastStreamSeq = ("Nats-Last-Stream".freeze)
21
+ # rubocop:disable Naming/ConstantName
22
+
23
+ Status = "Status"
24
+ Desc = "Description"
25
+ MsgID = "Nats-Msg-Id"
26
+ ExpectedStream = "Nats-Expected-Stream"
27
+ ExpectedLastSeq = "Nats-Expected-Last-Sequence"
28
+ ExpectedLastSubjSeq = "Nats-Expected-Last-Subject-Sequence"
29
+ ExpectedLastMsgID = "Nats-Expected-Last-Msg-Id"
30
+ LastConsumerSeq = "Nats-Last-Consumer"
31
+ LastStreamSeq = "Nats-Last-Stream"
32
+
33
+ # rubocop:enable Naming/ConstantName
28
34
  end
29
35
  end
30
36
  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.
@@ -16,11 +18,15 @@ module NATS
16
18
  class JetStream
17
19
  module JS
18
20
  module Status
19
- CtrlMsg = ("100".freeze)
20
- NoMsgs = ("404".freeze)
21
- NotFound = ("404".freeze)
22
- RequestTimeout = ("408".freeze)
23
- ServiceUnavailable = ("503".freeze)
21
+ # rubocop:disable Naming/ConstantName
22
+
23
+ CtrlMsg = "100"
24
+ NoMsgs = "404"
25
+ NotFound = "404"
26
+ RequestTimeout = "408"
27
+ ServiceUnavailable = "503"
28
+
29
+ # rubocop:enable Naming/ConstantName
24
30
  end
25
31
  end
26
32
  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.
@@ -16,9 +18,9 @@ module NATS
16
18
  class JetStream
17
19
  module JS
18
20
  class Sub
19
- attr_reader :js, :stream, :consumer, :nms
21
+ attr_accessor :js, :stream, :consumer, :nms
20
22
 
21
- def initialize(opts={})
23
+ def initialize(opts = {})
22
24
  @js = opts[:js]
23
25
  @stream = opts[:stream]
24
26
  @consumer = opts[:consumer]
@@ -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,17 +14,17 @@
12
14
  # limitations under the License.
13
15
  #
14
16
 
15
- require_relative 'js/config'
16
- require_relative 'js/header'
17
- require_relative 'js/status'
18
- require_relative 'js/sub'
17
+ require_relative "js/config"
18
+ require_relative "js/header"
19
+ require_relative "js/status"
20
+ require_relative "js/sub"
19
21
 
20
22
  module NATS
21
23
  class JetStream
22
24
  # Misc internal functions to support JS API.
23
25
  # @private
24
26
  module JS
25
- DefaultAPIPrefix = ("$JS.API".freeze)
27
+ DefaultAPIPrefix = "$JS.API" # rubocop:disable Naming/ConstantName
26
28
 
27
29
  class << self
28
30
  def next_req_to_json(next_req)
@@ -34,14 +36,14 @@ module NATS
34
36
  end
35
37
 
36
38
  def is_status_msg(msg)
37
- return (!msg.nil? and (!msg.header.nil? and msg.header[Header::Status]))
39
+ (!msg.nil? and (!msg.header.nil? and msg.header[Header::Status]))
38
40
  end
39
41
 
40
42
  # check_503_error raises exception when a NATS::Msg has a 503 status header.
41
43
  # @param msg [NATS::Msg] The message with status headers.
42
44
  # @raise [NATS::JetStream::Error::ServiceUnavailable]
43
45
  def check_503_error(msg)
44
- return if msg.nil? or msg.header.nil?
46
+ return if msg.nil? || msg.header.nil?
45
47
  if msg.header[Header::Status] == Status::ServiceUnavailable
46
48
  raise ::NATS::JetStream::Error::ServiceUnavailable
47
49
  end
@@ -59,7 +61,7 @@ module NATS
59
61
  check_503_error(msg)
60
62
  code = msg.header[JS::Header::Status]
61
63
  desc = msg.header[JS::Header::Desc]
62
- return ::NATS::JetStream::API::Error.new({code: code, description: desc})
64
+ ::NATS::JetStream::API::Error.new({code: code, description: desc})
63
65
  end
64
66
 
65
67
  # from_error takes an API response that errored and maps the error