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.
@@ -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,32 +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
-
123
- # NATS v2.10 features
124
- :metadata, :filter_subjects, :max_bytes,
125
- keyword_init: true) do
126
- 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 = {})
127
129
  # Filter unrecognized fields just in case.
128
130
  rem = opts.keys - members
129
131
  opts.delete_if { |k| rem.include?(k) }
130
- super(opts)
132
+ super
131
133
  end
132
134
  end
133
135
 
@@ -196,12 +198,13 @@ module NATS
196
198
  :allow_direct,
197
199
  :mirror_direct,
198
200
  :metadata,
199
- keyword_init: true) do
200
- def initialize(opts={})
201
+ keyword_init: true
202
+ ) do
203
+ def initialize(opts = {})
201
204
  # Filter unrecognized fields just in case.
202
205
  rem = opts.keys - members
203
206
  opts.delete_if { |k| rem.include?(k) }
204
- super(opts)
207
+ super
205
208
  end
206
209
  end
207
210
 
@@ -218,8 +221,8 @@ module NATS
218
221
  # @!attribute domain
219
222
  # @return [String]
220
223
  StreamInfo = Struct.new(:type, :config, :created, :state, :domain,
221
- keyword_init: true) do
222
- def initialize(opts={})
224
+ keyword_init: true) do
225
+ def initialize(opts = {})
223
226
  opts[:config] = StreamConfig.new(opts[:config])
224
227
  opts[:state] = StreamState.new(opts[:state])
225
228
  opts[:created] = ::Time.parse(opts[:created])
@@ -227,7 +230,7 @@ module NATS
227
230
  # Filter fields and freeze.
228
231
  rem = opts.keys - members
229
232
  opts.delete_if { |k| rem.include?(k) }
230
- super(opts)
233
+ super
231
234
  freeze
232
235
  end
233
236
  end
@@ -245,12 +248,12 @@ module NATS
245
248
  # @!attribute consumer_count
246
249
  # @return [Integer]
247
250
  StreamState = Struct.new(:messages, :bytes, :first_seq, :first_ts,
248
- :last_seq, :last_ts, :consumer_count,
249
- keyword_init: true) do
250
- def initialize(opts={})
251
+ :last_seq, :last_ts, :consumer_count,
252
+ keyword_init: true) do
253
+ def initialize(opts = {})
251
254
  rem = opts.keys - members
252
255
  opts.delete_if { |k| rem.include?(k) }
253
- super(opts)
256
+ super
254
257
  end
255
258
  end
256
259
 
@@ -267,13 +270,13 @@ module NATS
267
270
  # @!attribute did_create
268
271
  # @return [Boolean]
269
272
  StreamCreateResponse = Struct.new(:type, :config, :created, :state, :did_create,
270
- keyword_init: true) do
271
- def initialize(opts={})
273
+ keyword_init: true) do
274
+ def initialize(opts = {})
272
275
  rem = opts.keys - members
273
276
  opts.delete_if { |k| rem.include?(k) }
274
277
  opts[:config] = StreamConfig.new(opts[:config])
275
278
  opts[:state] = StreamState.new(opts[:state])
276
- super(opts)
279
+ super
277
280
  freeze
278
281
  end
279
282
  end
@@ -297,11 +300,11 @@ module NATS
297
300
  # Filter out members not present.
298
301
  rem = opts.keys - members
299
302
  opts.delete_if { |k| rem.include?(k) }
300
- super(opts)
303
+ super
301
304
  end
302
305
 
303
306
  def sequence
304
- self.seq
307
+ seq
305
308
  end
306
309
  end
307
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