nats-pure 2.6.0 → 2.7.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 +63 -0
- data/README.md +83 -0
- data/lib/nats/io/jetstream/api.rb +213 -5
- data/lib/nats/io/jetstream/errors.rb +25 -0
- data/lib/nats/io/jetstream/header.rb +115 -0
- data/lib/nats/io/jetstream/js/header.rb +1 -0
- data/lib/nats/io/jetstream/js/status.rb +1 -0
- data/lib/nats/io/jetstream/js.rb +30 -2
- data/lib/nats/io/jetstream/manager.rb +246 -66
- data/lib/nats/io/jetstream/msg/ack_methods.rb +8 -2
- data/lib/nats/io/jetstream/pull_subscription.rb +288 -190
- data/lib/nats/io/jetstream.rb +97 -8
- data/lib/nats/io/kv/api.rb +4 -0
- data/lib/nats/io/kv/bucket_status.rb +12 -0
- data/lib/nats/io/kv/manager.rb +7 -1
- data/lib/nats/io/kv.rb +16 -5
- data/lib/nats/io/subscription.rb +10 -9
- data/lib/nats/io/version.rb +1 -1
- data/sig/nats/io/jetstream/api.rbs +12 -3
- data/sig/nats/io/jetstream/errors.rbs +12 -0
- data/sig/nats/io/jetstream/header.rbs +33 -0
- data/sig/nats/io/jetstream/js/header.rbs +1 -0
- data/sig/nats/io/jetstream/js/status.rbs +1 -0
- data/sig/nats/io/jetstream/js.rbs +3 -1
- data/sig/nats/io/jetstream/manager.rbs +21 -1
- data/sig/nats/io/jetstream/pull_subscription.rbs +40 -2
- data/sig/nats/io/jetstream.rbs +9 -1
- data/sig/nats/io/kv/bucket_status.rbs +4 -0
- metadata +3 -1
data/lib/nats/io/jetstream/js.rb
CHANGED
|
@@ -32,11 +32,28 @@ module NATS
|
|
|
32
32
|
req[:batch] = next_req[:batch]
|
|
33
33
|
req[:expires] = next_req[:expires].to_i if next_req[:expires]
|
|
34
34
|
req[:no_wait] = next_req[:no_wait] if next_req[:no_wait]
|
|
35
|
+
# Priority groups (requires nats-server v2.11.0).
|
|
36
|
+
req.merge!(next_req.slice(:group, :min_pending, :min_ack_pending, :priority, :id).compact)
|
|
35
37
|
req.to_json
|
|
36
38
|
end
|
|
37
39
|
|
|
40
|
+
# parse_time parses a time from the server, which sends Go's zero
|
|
41
|
+
# time for a time that is not set.
|
|
42
|
+
def parse_time(time)
|
|
43
|
+
return if time.nil?
|
|
44
|
+
|
|
45
|
+
time = ::Time.parse(time)
|
|
46
|
+
time unless time.year == 1
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# is_status_msg tells whether the server sent a message as a status:
|
|
50
|
+
# one with a Status header and no reply. A message of a stream can
|
|
51
|
+
# have a Status header too, but a consumer delivers it with a reply
|
|
52
|
+
# to ack it.
|
|
38
53
|
def is_status_msg(msg)
|
|
39
|
-
|
|
54
|
+
return false if msg.nil? || msg.header.nil?
|
|
55
|
+
|
|
56
|
+
!msg.header[Header::Status].nil? && msg.reply.to_s.empty?
|
|
40
57
|
end
|
|
41
58
|
|
|
42
59
|
# check_503_error raises exception when a NATS::Msg has a 503 status header.
|
|
@@ -61,6 +78,8 @@ module NATS
|
|
|
61
78
|
check_503_error(msg)
|
|
62
79
|
code = msg.header[JS::Header::Status]
|
|
63
80
|
desc = msg.header[JS::Header::Desc]
|
|
81
|
+
return ::NATS::JetStream::Error::PinIdMismatch.new({description: desc}) if code == Status::PinIdMismatch
|
|
82
|
+
|
|
64
83
|
::NATS::JetStream::API::Error.new({code: code, description: desc})
|
|
65
84
|
end
|
|
66
85
|
|
|
@@ -83,7 +102,16 @@ module NATS
|
|
|
83
102
|
::NATS::JetStream::Error::NotFound.new(err)
|
|
84
103
|
end
|
|
85
104
|
when 400
|
|
86
|
-
|
|
105
|
+
case err[:err_code]
|
|
106
|
+
when 10148
|
|
107
|
+
::NATS::JetStream::Error::ConsumerAlreadyExists.new(err)
|
|
108
|
+
when 10149
|
|
109
|
+
::NATS::JetStream::Error::ConsumerDoesNotExist.new(err)
|
|
110
|
+
when 10204
|
|
111
|
+
::NATS::JetStream::Error::ConsumerInvalidReset.new(err)
|
|
112
|
+
else
|
|
113
|
+
::NATS::JetStream::Error::BadRequest.new(err)
|
|
114
|
+
end
|
|
87
115
|
else
|
|
88
116
|
::NATS::JetStream::API::Error.new(err)
|
|
89
117
|
end
|
|
@@ -28,6 +28,23 @@ module NATS
|
|
|
28
28
|
#
|
|
29
29
|
#
|
|
30
30
|
module Manager
|
|
31
|
+
# The defaults of the stream settings of nats-server 2.11 to 2.14,
|
|
32
|
+
# which are not sent, as nats.go does not send them either, so that
|
|
33
|
+
# servers that do not know the settings take configs that leave them
|
|
34
|
+
# at their defaults. Nor is discard_new_per_subject at its default,
|
|
35
|
+
# which the client did not send before it knew the setting.
|
|
36
|
+
UNSENT_STREAM_DEFAULTS = {
|
|
37
|
+
discard_new_per_subject: [false],
|
|
38
|
+
allow_msg_ttl: [false],
|
|
39
|
+
subject_delete_marker_ttl: [0],
|
|
40
|
+
allow_msg_counter: [false],
|
|
41
|
+
allow_atomic: [false],
|
|
42
|
+
allow_msg_schedules: [false],
|
|
43
|
+
persist_mode: ["", "default"],
|
|
44
|
+
allow_batched: [false]
|
|
45
|
+
}.freeze
|
|
46
|
+
private_constant :UNSENT_STREAM_DEFAULTS
|
|
47
|
+
|
|
31
48
|
# add_stream creates a stream with a given config.
|
|
32
49
|
# @param config [JetStream::API::StreamConfig] Configuration of the stream to create.
|
|
33
50
|
# @param params [Hash] Options to customize API request.
|
|
@@ -44,8 +61,7 @@ module NATS
|
|
|
44
61
|
raise ArgumentError.new("Spaces, tabs, period (.), greater than (>) or asterisk (*) are prohibited in stream names") if stream =~ /(\s|\.|>|\*)/
|
|
45
62
|
req_subject = "#{@prefix}.STREAM.CREATE.#{stream}"
|
|
46
63
|
|
|
47
|
-
|
|
48
|
-
result = api_request(req_subject, cfg.to_json, params)
|
|
64
|
+
result = api_request(req_subject, stream_config_json(config), params)
|
|
49
65
|
JetStream::API::StreamCreateResponse.new(result)
|
|
50
66
|
end
|
|
51
67
|
|
|
@@ -62,7 +78,11 @@ module NATS
|
|
|
62
78
|
JetStream::API::StreamInfo.new(result)
|
|
63
79
|
end
|
|
64
80
|
|
|
65
|
-
# update_stream edits an existed stream with a given config.
|
|
81
|
+
# update_stream edits an existed stream with a given config. The config
|
|
82
|
+
# replaces the stream's, so pass all of it, as from stream_info.
|
|
83
|
+
# Updating a mirror without its mirror setting makes it a stream of its
|
|
84
|
+
# own for good, no longer a mirror (nats-server v2.12.0; older servers
|
|
85
|
+
# refuse the update).
|
|
66
86
|
# @param config [JetStream::API::StreamConfig] Configuration of the stream to create.
|
|
67
87
|
# @param params [Hash] Options to customize API request.
|
|
68
88
|
# @option params [Float] :timeout Time to wait for response.
|
|
@@ -77,8 +97,7 @@ module NATS
|
|
|
77
97
|
raise ArgumentError.new(":name is required to create streams") unless stream
|
|
78
98
|
raise ArgumentError.new("Spaces, tabs, period (.), greater than (>) or asterisk (*) are prohibited in stream names") if stream =~ /(\s|\.|>|\*)/
|
|
79
99
|
req_subject = "#{@prefix}.STREAM.UPDATE.#{stream}"
|
|
80
|
-
|
|
81
|
-
result = api_request(req_subject, cfg.to_json, params)
|
|
100
|
+
result = api_request(req_subject, stream_config_json(config), params)
|
|
82
101
|
JetStream::API::StreamCreateResponse.new(result)
|
|
83
102
|
end
|
|
84
103
|
|
|
@@ -95,75 +114,45 @@ module NATS
|
|
|
95
114
|
result[:success]
|
|
96
115
|
end
|
|
97
116
|
|
|
98
|
-
# add_consumer creates a consumer with a given config
|
|
117
|
+
# add_consumer creates a consumer with a given config, or updates the
|
|
118
|
+
# consumer if one with the same name already exists.
|
|
99
119
|
# @param stream [String] Name of the stream.
|
|
100
120
|
# @param config [JetStream::API::ConsumerConfig] Configuration of the consumer to create.
|
|
101
121
|
# @param params [Hash] Options to customize API request.
|
|
102
122
|
# @option params [Float] :timeout Time to wait for response.
|
|
103
123
|
# @return [JetStream::API::ConsumerInfo] The result of creating a Consumer.
|
|
104
124
|
def add_consumer(stream, config, params = {})
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
143
|
-
|
|
144
|
-
config[:ack_policy] ||= JS::Config::AckExplicit
|
|
145
|
-
# Check if have to normalize ack wait so that it is in nanoseconds for Go compat.
|
|
146
|
-
if config[:ack_wait]
|
|
147
|
-
raise ArgumentError.new("nats: invalid ack wait") unless config[:ack_wait].is_a?(Integer)
|
|
148
|
-
config[:ack_wait] = config[:ack_wait] * ::NATS::NANOSECONDS
|
|
149
|
-
end
|
|
150
|
-
if config[:inactive_threshold]
|
|
151
|
-
raise ArgumentError.new("nats: invalid inactive threshold") unless config[:inactive_threshold].is_a?(Integer)
|
|
152
|
-
config[:inactive_threshold] = config[:inactive_threshold] * ::NATS::NANOSECONDS
|
|
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
|
|
125
|
+
upsert_consumer(stream, config, nil, params)
|
|
126
|
+
end
|
|
158
127
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
128
|
+
# create_consumer creates a consumer with a given config. Creating a
|
|
129
|
+
# consumer that already exists with the same config succeeds; one that
|
|
130
|
+
# exists with a different config raises ConsumerAlreadyExists.
|
|
131
|
+
# Requires nats-server v2.10.0.
|
|
132
|
+
# @param stream [String] Name of the stream.
|
|
133
|
+
# @param config [JetStream::API::ConsumerConfig] Configuration of the consumer to create.
|
|
134
|
+
# @param params [Hash] Options to customize API request.
|
|
135
|
+
# @option params [Float] :timeout Time to wait for response.
|
|
136
|
+
# @return [JetStream::API::ConsumerInfo] The result of creating a Consumer.
|
|
137
|
+
def create_consumer(stream, config, params = {})
|
|
138
|
+
upsert_consumer(stream, config, "create", params)
|
|
139
|
+
end
|
|
164
140
|
|
|
165
|
-
|
|
166
|
-
|
|
141
|
+
# update_consumer replaces the config of an existing consumer, named by
|
|
142
|
+
# the config's name or durable_name, so fields left out take their
|
|
143
|
+
# defaults: pass the whole config, with the changes. The config from
|
|
144
|
+
# consumer_info lacks the settings this client does not know, and has
|
|
145
|
+
# its durations rounded down to whole seconds. A consumer that does
|
|
146
|
+
# not exist raises ConsumerDoesNotExist; the server decides which
|
|
147
|
+
# fields may change, and keeps the pause of the consumer, which
|
|
148
|
+
# pause_consumer and resume_consumer change. Requires nats-server v2.10.0.
|
|
149
|
+
# @param stream [String] Name of the stream.
|
|
150
|
+
# @param config [JetStream::API::ConsumerConfig] New configuration of the consumer.
|
|
151
|
+
# @param params [Hash] Options to customize API request.
|
|
152
|
+
# @option params [Float] :timeout Time to wait for response.
|
|
153
|
+
# @return [JetStream::API::ConsumerInfo] The updated Consumer.
|
|
154
|
+
def update_consumer(stream, config, params = {})
|
|
155
|
+
upsert_consumer(stream, config, "update", params)
|
|
167
156
|
end
|
|
168
157
|
|
|
169
158
|
# consumer_info retrieves the current status of a consumer.
|
|
@@ -196,6 +185,96 @@ module NATS
|
|
|
196
185
|
result[:success]
|
|
197
186
|
end
|
|
198
187
|
|
|
188
|
+
# pause_consumer pauses a consumer, so that it delivers no messages
|
|
189
|
+
# until the given time. Requires nats-server v2.11.0: older servers
|
|
190
|
+
# let the request time out.
|
|
191
|
+
# @param stream [String] Name of the stream.
|
|
192
|
+
# @param consumer [String] Name of the consumer.
|
|
193
|
+
# @param pause_until [Time, String] When to resume, as a Time or as an RFC 3339 String.
|
|
194
|
+
# @param params [Hash] Options to customize API request.
|
|
195
|
+
# @option params [Float] :timeout Time to wait for response.
|
|
196
|
+
# @return [JetStream::API::ConsumerPauseResponse]
|
|
197
|
+
# @raise [ArgumentError] When pause_until is nil: resume_consumer resumes.
|
|
198
|
+
# @raise [JetStream::Error::StreamNotFound] When the stream does not exist.
|
|
199
|
+
# @raise [JetStream::Error::ConsumerNotFound] When the consumer does not exist.
|
|
200
|
+
# @raise [NATS::Timeout] With a server before v2.11.0.
|
|
201
|
+
def pause_consumer(stream, consumer, pause_until, params = {})
|
|
202
|
+
raise ArgumentError.new("nats: a time to pause until is required, resume_consumer resumes") if pause_until.nil?
|
|
203
|
+
|
|
204
|
+
request_pause(stream, consumer, {pause_until: rfc3339(pause_until)}, params)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# resume_consumer resumes a paused consumer. Requires nats-server
|
|
208
|
+
# v2.11.0: older servers let the request time out.
|
|
209
|
+
# @param stream [String] Name of the stream.
|
|
210
|
+
# @param consumer [String] Name of the consumer.
|
|
211
|
+
# @param params [Hash] Options to customize API request.
|
|
212
|
+
# @option params [Float] :timeout Time to wait for response.
|
|
213
|
+
# @return [JetStream::API::ConsumerPauseResponse]
|
|
214
|
+
# @raise [JetStream::Error::StreamNotFound] When the stream does not exist.
|
|
215
|
+
# @raise [JetStream::Error::ConsumerNotFound] When the consumer does not exist.
|
|
216
|
+
# @raise [NATS::Timeout] With a server before v2.11.0.
|
|
217
|
+
def resume_consumer(stream, consumer, params = {})
|
|
218
|
+
request_pause(stream, consumer, {}, params)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# unpin_consumer unpins a priority group of a consumer with the
|
|
222
|
+
# pinned_client priority policy from its subscription, so that the
|
|
223
|
+
# next subscription to pull is pinned instead. The server tells the
|
|
224
|
+
# subscription that was pinned once it has a message for its pull, and
|
|
225
|
+
# its fetch then raises PinIdMismatch; without messages, the fetch
|
|
226
|
+
# times out. Requires nats-server v2.11.0.
|
|
227
|
+
# @param stream [String] Name of the stream.
|
|
228
|
+
# @param consumer [String] Name of the consumer.
|
|
229
|
+
# @param group [String] Name of the priority group.
|
|
230
|
+
# @param params [Hash] Options to customize API request.
|
|
231
|
+
# @option params [Float] :timeout Time to wait for response.
|
|
232
|
+
# @return [Boolean]
|
|
233
|
+
# @raise [JetStream::Error::StreamNotFound] When the stream does not exist.
|
|
234
|
+
# @raise [JetStream::Error::ConsumerNotFound] When the consumer does not exist.
|
|
235
|
+
# @raise [JetStream::Error::BadRequest] When the consumer has no such group.
|
|
236
|
+
# @raise [NATS::Timeout] With a server before v2.11.0.
|
|
237
|
+
def unpin_consumer(stream, consumer, group, params = {})
|
|
238
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
|
239
|
+
raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil? || consumer.empty?
|
|
240
|
+
|
|
241
|
+
req_subject = "#{@prefix}.CONSUMER.UNPIN.#{stream}.#{consumer}"
|
|
242
|
+
api_request(req_subject, {group: group}.to_json, params)
|
|
243
|
+
true
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# reset_consumer resets the delivery state of a consumer, as if it had
|
|
247
|
+
# been created again to start from a stream sequence: by default the
|
|
248
|
+
# one after its ack floor, so that it redelivers the messages that
|
|
249
|
+
# await acks. Only a consumer that delivers all messages, or from a
|
|
250
|
+
# start sequence or time, can be given a sequence, and not one before
|
|
251
|
+
# its start. Requires nats-server v2.14.0: an older server, like a
|
|
252
|
+
# stream or consumer that does not exist, lets the request time out.
|
|
253
|
+
# @param stream [String] Name of the stream.
|
|
254
|
+
# @param consumer [String] Name of the consumer.
|
|
255
|
+
# @param params [Hash] Options to customize API request.
|
|
256
|
+
# @option params [Integer] :seq Stream sequence to deliver from; 0, like
|
|
257
|
+
# none, for the one after the ack floor.
|
|
258
|
+
# @option params [Float] :timeout Time to wait for response.
|
|
259
|
+
# @return [JetStream::API::ConsumerResetResponse]
|
|
260
|
+
# @raise [ArgumentError] When seq is not an integer of 0 or more.
|
|
261
|
+
# @raise [JetStream::Error::ConsumerInvalidReset] When the consumer cannot be reset to seq.
|
|
262
|
+
# @raise [NATS::Timeout] When the stream or consumer does not exist, or the server
|
|
263
|
+
# cannot reset consumers.
|
|
264
|
+
def reset_consumer(stream, consumer, params = {})
|
|
265
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
|
266
|
+
raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil? || consumer.empty?
|
|
267
|
+
seq = params[:seq]
|
|
268
|
+
if !seq.nil? && !(seq.is_a?(Integer) && seq >= 0)
|
|
269
|
+
raise ArgumentError.new("nats: seq should be an integer of 0 or more")
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
req_subject = "#{@prefix}.CONSUMER.RESET.#{stream}.#{consumer}"
|
|
273
|
+
req = {seq: seq}.compact
|
|
274
|
+
result = api_request(req_subject, req.to_json, params.except(:seq))
|
|
275
|
+
JetStream::API::ConsumerResetResponse.new(result)
|
|
276
|
+
end
|
|
277
|
+
|
|
199
278
|
# find_stream_name_by_subject does a lookup for the stream to which
|
|
200
279
|
# the subject belongs.
|
|
201
280
|
# @param subject [String] The subject that belongs to a stream.
|
|
@@ -260,6 +339,102 @@ module NATS
|
|
|
260
339
|
|
|
261
340
|
private
|
|
262
341
|
|
|
342
|
+
# upsert_consumer sends a consumer create request. The action is
|
|
343
|
+
# "create", "update", or nil to create or update.
|
|
344
|
+
def upsert_consumer(stream, config, action, params)
|
|
345
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
|
346
|
+
# Work on a copy: the durations are converted to nanoseconds below,
|
|
347
|
+
# and the caller may send the same config again.
|
|
348
|
+
config = if !config.is_a?(JetStream::API::ConsumerConfig)
|
|
349
|
+
JetStream::API::ConsumerConfig.new(config)
|
|
350
|
+
else
|
|
351
|
+
config.dup
|
|
352
|
+
end
|
|
353
|
+
config[:name] ||= config[:durable_name]
|
|
354
|
+
if action == "update" && (config[:name].nil? || config[:name].empty?)
|
|
355
|
+
raise ArgumentError.new("nats: the consumer to update needs a name or durable name")
|
|
356
|
+
end
|
|
357
|
+
req_subject = if config[:name]
|
|
358
|
+
###############################################################################
|
|
359
|
+
# #
|
|
360
|
+
# Using names is the supported way of creating consumers (NATS +v2.9.0. #
|
|
361
|
+
# #
|
|
362
|
+
###############################################################################
|
|
363
|
+
if config[:filter_subject] && config[:filter_subject] != ">"
|
|
364
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}.#{config[:filter_subject]}"
|
|
365
|
+
else
|
|
366
|
+
##############################################################################
|
|
367
|
+
# #
|
|
368
|
+
# Endpoint to support creating ANY consumer with multi-filters (NATS +v2.10) #
|
|
369
|
+
# #
|
|
370
|
+
##############################################################################
|
|
371
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}.#{config[:name]}"
|
|
372
|
+
end
|
|
373
|
+
elsif config[:durable_name]
|
|
374
|
+
###############################################################################
|
|
375
|
+
# #
|
|
376
|
+
# Endpoint to support creating DURABLES before NATS v2.9.0. #
|
|
377
|
+
# #
|
|
378
|
+
###############################################################################
|
|
379
|
+
"#{@prefix}.CONSUMER.DURABLE.CREATE.#{stream}.#{config[:durable_name]}"
|
|
380
|
+
else
|
|
381
|
+
###############################################################################
|
|
382
|
+
# #
|
|
383
|
+
# Endpoint to support creating EPHEMERALS before NATS v2.9.0. #
|
|
384
|
+
# #
|
|
385
|
+
###############################################################################
|
|
386
|
+
"#{@prefix}.CONSUMER.CREATE.#{stream}"
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
config[:ack_policy] ||= JS::Config::AckExplicit
|
|
390
|
+
# Check if have to normalize ack wait so that it is in nanoseconds for Go compat.
|
|
391
|
+
if config[:ack_wait]
|
|
392
|
+
raise ArgumentError.new("nats: invalid ack wait") unless config[:ack_wait].is_a?(Integer)
|
|
393
|
+
config[:ack_wait] = config[:ack_wait] * ::NATS::NANOSECONDS
|
|
394
|
+
end
|
|
395
|
+
if config[:inactive_threshold]
|
|
396
|
+
raise ArgumentError.new("nats: invalid inactive threshold") unless config[:inactive_threshold].is_a?(Integer)
|
|
397
|
+
config[:inactive_threshold] = config[:inactive_threshold] * ::NATS::NANOSECONDS
|
|
398
|
+
end
|
|
399
|
+
if config[:idle_heartbeat]
|
|
400
|
+
raise ArgumentError.new("nats: invalid idle heartbeat") unless config[:idle_heartbeat].is_a?(Integer)
|
|
401
|
+
config[:idle_heartbeat] = config[:idle_heartbeat] * ::NATS::NANOSECONDS
|
|
402
|
+
end
|
|
403
|
+
if config[:priority_timeout]
|
|
404
|
+
raise ArgumentError.new("nats: invalid priority timeout") unless config[:priority_timeout].is_a?(Integer)
|
|
405
|
+
config[:priority_timeout] = config[:priority_timeout] * ::NATS::NANOSECONDS
|
|
406
|
+
end
|
|
407
|
+
config[:pause_until] = rfc3339(config[:pause_until])
|
|
408
|
+
|
|
409
|
+
cfg = config.to_h.compact
|
|
410
|
+
req = {
|
|
411
|
+
stream_name: stream,
|
|
412
|
+
config: cfg
|
|
413
|
+
}
|
|
414
|
+
# Without an action the server creates or updates.
|
|
415
|
+
req[:action] = action if action
|
|
416
|
+
|
|
417
|
+
result = api_request(req_subject, req.to_json, params)
|
|
418
|
+
JetStream::API::ConsumerInfo.new(result).freeze
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# request_pause sends a consumer pause request, which resumes the
|
|
422
|
+
# consumer when it has no pause time.
|
|
423
|
+
def request_pause(stream, consumer, req, params)
|
|
424
|
+
raise JetStream::Error::InvalidStreamName.new("nats: invalid stream name") if stream.nil? || stream.empty?
|
|
425
|
+
raise JetStream::Error::InvalidConsumerName.new("nats: invalid consumer name") if consumer.nil? || consumer.empty?
|
|
426
|
+
|
|
427
|
+
req_subject = "#{@prefix}.CONSUMER.PAUSE.#{stream}.#{consumer}"
|
|
428
|
+
result = api_request(req_subject, req.to_json, params)
|
|
429
|
+
JetStream::API::ConsumerPauseResponse.new(result)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# rfc3339 formats a Time as the server expects it; a String is
|
|
433
|
+
# sent as is.
|
|
434
|
+
def rfc3339(time)
|
|
435
|
+
time.is_a?(Time) ? time.getutc.iso8601(9) : time
|
|
436
|
+
end
|
|
437
|
+
|
|
263
438
|
def api_request(req_subject, req = "", params = {})
|
|
264
439
|
params[:timeout] ||= @opts[:timeout]
|
|
265
440
|
msg = begin
|
|
@@ -300,6 +475,11 @@ module NATS
|
|
|
300
475
|
|
|
301
476
|
raw_msg
|
|
302
477
|
end
|
|
478
|
+
|
|
479
|
+
# stream_config_json makes the request to create or update a stream.
|
|
480
|
+
def stream_config_json(config)
|
|
481
|
+
config.to_h.compact.reject { |key, value| UNSENT_STREAM_DEFAULTS[key]&.include?(value) }.to_json
|
|
482
|
+
end
|
|
303
483
|
end
|
|
304
484
|
end
|
|
305
485
|
end
|
|
@@ -58,13 +58,19 @@ module NATS
|
|
|
58
58
|
resp
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
# term tells the server not to redeliver the message. A :reason is
|
|
62
|
+
# passed on in the server's terminated advisory. Servers before
|
|
63
|
+
# v2.10.4 do not terminate a message given a reason, so it will
|
|
64
|
+
# be redelivered.
|
|
61
65
|
def term(**params)
|
|
62
66
|
ensure_is_acked_once!
|
|
63
67
|
|
|
68
|
+
reason = params.delete(:reason)
|
|
69
|
+
payload = reason.to_s.strip.empty? ? Ack::Term : "#{Ack::Term} #{reason}"
|
|
64
70
|
resp = if params[:timeout]
|
|
65
|
-
@nc.request(@reply,
|
|
71
|
+
@nc.request(@reply, payload, **params)
|
|
66
72
|
else
|
|
67
|
-
@nc.publish(@reply,
|
|
73
|
+
@nc.publish(@reply, payload)
|
|
68
74
|
end
|
|
69
75
|
@sub.synchronize { @ackd = true }
|
|
70
76
|
|