nats 0.9.2 → 0.10.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/README.md +11 -9
- data/lib/nats/client.rb +171 -14
- data/lib/nats/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8caff8d7b6a0c87a312c9942174fe3c455e2cfc1c3abdb7c6baf7eb5db7445ef
|
4
|
+
data.tar.gz: 2dd5eb84f34dea3c6509c732b8da35d095af409fb955de312bc75c0b5306c7b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d8e2aa2738f152cc9f15bb1a5759714062535d55a6c449fc0a55e61b2cd59f45d37e39129fade9acf9cb0a82c2f5bf555f00fd82302e97ec9ec603ee2d2e493
|
7
|
+
data.tar.gz: '07828fd12c5c5a89eebfabaf8dae0315fa0bb0eb5dd013fee13282a63a5c037e04d2a072424fd97c266cabeb9d465ad3f79b66c4ace6c1280af85a4acf5da203'
|
data/README.md
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
A [Ruby](http://ruby-lang.org) client for the [NATS messaging system](https://nats.io).
|
4
4
|
|
5
5
|
[](https://www.apache.org/licenses/LICENSE-2.0)
|
6
|
-
[](http://travis-ci.org/nats-io/ruby-nats) [](http://travis-ci.org/nats-io/ruby-nats) [](https://rubygems.org/gems/nats/versions/0.10.0) [](https://www.rubydoc.info/gems/nats)
|
7
7
|
|
8
8
|
## Supported Platforms
|
9
9
|
|
10
10
|
This gem and the client are known to work on the following Ruby platforms:
|
11
11
|
|
12
|
-
- MRI 2.
|
13
|
-
- JRuby 9.1.2.0, 9.1.15.0
|
12
|
+
- MRI 2.3.0, 2.4.0, 2.5.0
|
13
|
+
- JRuby 9.1.2.0, 9.1.15.0, 9.2.0.0
|
14
14
|
|
15
15
|
If you're looking for a non-EventMachine alternative, check out the [nats-pure](https://github.com/nats-io/pure-ruby-nats) gem.
|
16
16
|
|
@@ -108,11 +108,10 @@ end
|
|
108
108
|
|
109
109
|
### Auto discovery
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
those defined explicitly on connect:
|
111
|
+
The client also auto discovers new nodes announced by the server as
|
112
|
+
they attach to the cluster. Reconnection logic parameters such as
|
113
|
+
time to back-off on failure and max attempts apply the same to both
|
114
|
+
discovered nodes and those defined explicitly on connect:
|
116
115
|
|
117
116
|
```ruby
|
118
117
|
opts = {
|
@@ -149,7 +148,10 @@ NATS.unsubscribe(sid, MAX_WANTED)
|
|
149
148
|
# Multiple connections
|
150
149
|
NATS.subscribe('test') do |msg|
|
151
150
|
puts "received msg"
|
152
|
-
|
151
|
+
|
152
|
+
# Gracefully disconnect from NATS after handling
|
153
|
+
# messages that have already been delivered by server.
|
154
|
+
NATS.drain
|
153
155
|
end
|
154
156
|
|
155
157
|
# Form second connection to send message on
|
data/lib/nats/client.rb
CHANGED
@@ -42,6 +42,9 @@ module NATS
|
|
42
42
|
DEFAULT_PING_INTERVAL = 120
|
43
43
|
DEFAULT_PING_MAX = 2
|
44
44
|
|
45
|
+
# Drain mode support
|
46
|
+
DEFAULT_DRAIN_TIMEOUT = 30
|
47
|
+
|
45
48
|
# Protocol
|
46
49
|
# @private
|
47
50
|
MSG = /\AMSG\s+([^\s]+)\s+([^\s]+)\s+(([^\s]+)[^\S\r\n]+)?(\d+)\r\n/i #:nodoc:
|
@@ -93,6 +96,7 @@ module NATS
|
|
93
96
|
# Create and return a connection to the server with the given options.
|
94
97
|
# The optional block will be called when the connection has been completed.
|
95
98
|
#
|
99
|
+
# @param [String] uri The URI or comma separated list of URIs of NATS servers to connect to.
|
96
100
|
# @param [Hash] opts
|
97
101
|
# @option opts [String|URI] :uri The URI to connect to, example nats://localhost:4222
|
98
102
|
# @option opts [Boolean] :reconnect Boolean that can be used to suppress reconnect functionality.
|
@@ -107,7 +111,50 @@ module NATS
|
|
107
111
|
# @option opts [Integer] :max_outstanding_pings Integer that can be used to set the max number of outstanding pings before declaring a connection closed.
|
108
112
|
# @param [Block] &blk called when the connection is completed. Connection will be passed to the block.
|
109
113
|
# @return [NATS] connection to the server.
|
110
|
-
|
114
|
+
#
|
115
|
+
# @example Connect to local NATS server.
|
116
|
+
# NATS.connect do |nc|
|
117
|
+
# # ...
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# @example Setting custom server URI to connect.
|
121
|
+
# NATS.connect("nats://localhost:4222") do |nc|
|
122
|
+
# # ...
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
# @example Setting username and password to authenticate.
|
126
|
+
# NATS.connect("nats://user:password@localhost:4222") do |nc|
|
127
|
+
# # ...
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# @example Specifying explicit list of servers via options.
|
131
|
+
# NATS.connect(servers: ["nats://127.0.0.1:4222","nats://127.0.0.1:4223","nats://127.0.0.1:4224"]) do |nc|
|
132
|
+
# # ...
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# @example Using comma separated array to define list of servers.
|
136
|
+
# NATS.connect("nats://localhost:4223,nats://localhost:4224") do |nc|
|
137
|
+
# # ...
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# @example Only specifying endpoint uses NATS default scheme and port.
|
141
|
+
# NATS.connect("demo.nats.io") do |nc|
|
142
|
+
# # ...
|
143
|
+
# end
|
144
|
+
#
|
145
|
+
# @example Setting infinite reconnect retries with 2 seconds back off against custom URI.
|
146
|
+
# NATS.connect("demo.nats.io:4222", max_reconnect_attempts: -1, reconnect_time_wait: 2) do |nc|
|
147
|
+
# # ...
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
def connect(uri=nil, opts={}, &blk)
|
151
|
+
case uri
|
152
|
+
when String
|
153
|
+
opts[:uri] = process_uri(uri)
|
154
|
+
when Hash
|
155
|
+
opts = uri
|
156
|
+
end
|
157
|
+
|
111
158
|
# Defaults
|
112
159
|
opts[:verbose] = false if opts[:verbose].nil?
|
113
160
|
opts[:pedantic] = false if opts[:pedantic].nil?
|
@@ -117,6 +164,7 @@ module NATS
|
|
117
164
|
opts[:reconnect_time_wait] = RECONNECT_TIME_WAIT if opts[:reconnect_time_wait].nil?
|
118
165
|
opts[:ping_interval] = DEFAULT_PING_INTERVAL if opts[:ping_interval].nil?
|
119
166
|
opts[:max_outstanding_pings] = DEFAULT_PING_MAX if opts[:max_outstanding_pings].nil?
|
167
|
+
opts[:drain_timeout] = DEFAULT_DRAIN_TIMEOUT if opts[:drain_timeout].nil?
|
120
168
|
|
121
169
|
# Override with ENV
|
122
170
|
opts[:uri] ||= ENV['NATS_URI'] || DEFAULT_URI
|
@@ -129,10 +177,10 @@ module NATS
|
|
129
177
|
opts[:max_reconnect_attempts] = ENV['NATS_MAX_RECONNECT_ATTEMPTS'].to_i unless ENV['NATS_MAX_RECONNECT_ATTEMPTS'].nil?
|
130
178
|
opts[:reconnect_time_wait] = ENV['NATS_RECONNECT_TIME_WAIT'].to_i unless ENV['NATS_RECONNECT_TIME_WAIT'].nil?
|
131
179
|
opts[:name] ||= ENV['NATS_CONNECTION_NAME']
|
132
|
-
|
133
|
-
|
180
|
+
opts[:no_echo] ||= ENV['NATS_NO_ECHO'] || false
|
134
181
|
opts[:ping_interval] = ENV['NATS_PING_INTERVAL'].to_i unless ENV['NATS_PING_INTERVAL'].nil?
|
135
182
|
opts[:max_outstanding_pings] = ENV['NATS_MAX_OUTSTANDING_PINGS'].to_i unless ENV['NATS_MAX_OUTSTANDING_PINGS'].nil?
|
183
|
+
opts[:drain_timeout] ||= ENV['NATS_DRAIN_TIMEOUT'].to_i unless ENV['NATS_DRAIN_TIMEOUT'].nil?
|
136
184
|
|
137
185
|
uri = opts[:uris] || opts[:servers] || opts[:uri]
|
138
186
|
|
@@ -211,6 +259,16 @@ module NATS
|
|
211
259
|
@disconnect_cb = nil
|
212
260
|
end
|
213
261
|
|
262
|
+
# Drain gracefully disconnects from the server, letting
|
263
|
+
# subscribers process pending messages already sent by server and
|
264
|
+
# optionally calls the associated block.
|
265
|
+
# @param [Block] &blk called when drain is done and connection is closed.
|
266
|
+
def drain(&blk)
|
267
|
+
if (client and !client.draining? and (client.connected? || client.reconnecting?))
|
268
|
+
client.drain { blk.call if blk }
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
214
272
|
# @return [URI] Connected server
|
215
273
|
def connected_server
|
216
274
|
return nil unless client
|
@@ -229,6 +287,12 @@ module NATS
|
|
229
287
|
client.reconnecting?
|
230
288
|
end
|
231
289
|
|
290
|
+
# @return [Boolean] Draining state
|
291
|
+
def draining?
|
292
|
+
return false unless client
|
293
|
+
client.draining?
|
294
|
+
end
|
295
|
+
|
232
296
|
# @return [Hash] Options
|
233
297
|
def options
|
234
298
|
return {} unless client
|
@@ -343,16 +407,48 @@ module NATS
|
|
343
407
|
uri.host != 'localhost' && uri.host != '127.0.0.1'
|
344
408
|
end
|
345
409
|
|
410
|
+
def process_uri(uris)
|
411
|
+
connect_uris = []
|
412
|
+
uris.split(',').each do |uri|
|
413
|
+
opts = {}
|
414
|
+
|
415
|
+
# Scheme
|
416
|
+
if uri.include?("://")
|
417
|
+
scheme, uri = uri.split("://")
|
418
|
+
opts[:scheme] = scheme
|
419
|
+
else
|
420
|
+
opts[:scheme] = 'nats'
|
421
|
+
end
|
422
|
+
|
423
|
+
# UserInfo
|
424
|
+
if uri.include?("@")
|
425
|
+
userinfo, endpoint = uri.split("@")
|
426
|
+
host, port = endpoint.split(":")
|
427
|
+
opts[:userinfo] = userinfo
|
428
|
+
else
|
429
|
+
host, port = uri.split(":")
|
430
|
+
end
|
431
|
+
|
432
|
+
# Host and Port
|
433
|
+
opts[:host] = host || "localhost"
|
434
|
+
opts[:port] = port || DEFAULT_PORT
|
435
|
+
|
436
|
+
connect_uris << URI::Generic.build(opts)
|
437
|
+
end
|
438
|
+
|
439
|
+
connect_uris
|
440
|
+
end
|
346
441
|
end
|
347
442
|
|
348
443
|
attr_reader :connected, :connect_cb, :err_cb, :err_cb_overridden, :pongs_received #:nodoc:
|
349
|
-
attr_reader :closing, :reconnecting, :server_pool, :options, :server_info #:nodoc
|
444
|
+
attr_reader :closing, :reconnecting, :draining, :server_pool, :options, :server_info #:nodoc
|
350
445
|
attr_reader :msgs_received, :msgs_sent, :bytes_received, :bytes_sent, :pings
|
351
446
|
attr_reader :disconnect_cb, :close_cb
|
352
447
|
|
353
448
|
alias :connected? :connected
|
354
449
|
alias :closing? :closing
|
355
450
|
alias :reconnecting? :reconnecting
|
451
|
+
alias :draining? :draining
|
356
452
|
|
357
453
|
def initialize(options)
|
358
454
|
@options = options
|
@@ -383,6 +479,9 @@ module NATS
|
|
383
479
|
@resp_sub_prefix = nil
|
384
480
|
@nuid = NATS::NUID.new
|
385
481
|
|
482
|
+
# Drain mode
|
483
|
+
@draining = false
|
484
|
+
@drained_subs = false
|
386
485
|
send_connect_command
|
387
486
|
end
|
388
487
|
|
@@ -392,7 +491,7 @@ module NATS
|
|
392
491
|
# @param [String] opt_reply
|
393
492
|
# @param [Block] blk, closure called when publish has been processed by the server.
|
394
493
|
def publish(subject, msg=EMPTY_MSG, opt_reply=nil, &blk)
|
395
|
-
return unless subject
|
494
|
+
return unless subject and not @drained_subs
|
396
495
|
msg = msg.to_s
|
397
496
|
|
398
497
|
# Accounting
|
@@ -412,7 +511,7 @@ module NATS
|
|
412
511
|
# @param [Block] callback, called when a message is delivered.
|
413
512
|
# @return [Object] sid, Subject Identifier
|
414
513
|
def subscribe(subject, opts={}, &callback)
|
415
|
-
return unless subject
|
514
|
+
return unless subject and not draining?
|
416
515
|
sid = (@ssid += 1)
|
417
516
|
sub = @subs[sid] = { :subject => subject, :callback => callback, :received => 0 }
|
418
517
|
sub[:queue] = opts[:queue] if opts[:queue]
|
@@ -427,6 +526,7 @@ module NATS
|
|
427
526
|
# @param [Object] sid
|
428
527
|
# @param [Number] opt_max, optional number of responses to receive before auto-unsubscribing
|
429
528
|
def unsubscribe(sid, opt_max=nil)
|
529
|
+
return if draining?
|
430
530
|
opt_max_str = " #{opt_max}" unless opt_max.nil?
|
431
531
|
send_command("UNSUB #{sid}#{opt_max_str}#{CR_LF}")
|
432
532
|
return unless sub = @subs[sid]
|
@@ -434,6 +534,48 @@ module NATS
|
|
434
534
|
@subs.delete(sid) unless (sub[:max] && (sub[:received] < sub[:max]))
|
435
535
|
end
|
436
536
|
|
537
|
+
# Drain gracefully closes the connection.
|
538
|
+
# @param [Block] blk called when drain is done and connection is closed.
|
539
|
+
def drain(&blk)
|
540
|
+
return if draining? or closing?
|
541
|
+
@draining = true
|
542
|
+
|
543
|
+
# Remove interest in all subjects to stop receiving messages.
|
544
|
+
@subs.each do |sid, _|
|
545
|
+
send_command("UNSUB #{sid} #{CR_LF}")
|
546
|
+
end
|
547
|
+
|
548
|
+
# Roundtrip to ensure no more messages are received.
|
549
|
+
flush do
|
550
|
+
drain_timeout_timer, draining_timer = nil, nil
|
551
|
+
drain_timeout_timer = EM.add_timer(options[:drain_timeout]) do
|
552
|
+
EM.cancel_timer(draining_timer)
|
553
|
+
|
554
|
+
# Report the timeout via the error callback and just close
|
555
|
+
err_cb.call(NATS::ClientError.new("Drain Timeout"))
|
556
|
+
@draining = false
|
557
|
+
close unless closing?
|
558
|
+
blk.call if blk
|
559
|
+
end
|
560
|
+
|
561
|
+
# Periodically check for the pending data to be empty.
|
562
|
+
draining_timer = EM.add_periodic_timer(0.1) do
|
563
|
+
next unless closing? or @buf.nil? or @buf.empty?
|
564
|
+
|
565
|
+
# Subscriptions have been drained already so disallow publishing.
|
566
|
+
@drained_subs = true
|
567
|
+
next unless pending_data_size == 0
|
568
|
+
EM.cancel_timer(draining_timer)
|
569
|
+
EM.cancel_timer(drain_timeout_timer)
|
570
|
+
|
571
|
+
# We're done draining and can close now.
|
572
|
+
@draining = false
|
573
|
+
close unless closing?
|
574
|
+
blk.call if blk
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
437
579
|
# Return the active subscription count.
|
438
580
|
# @return [Number]
|
439
581
|
def subscription_count
|
@@ -628,7 +770,7 @@ module NATS
|
|
628
770
|
end
|
629
771
|
|
630
772
|
def auth_connection?
|
631
|
-
!@uri.user.nil?
|
773
|
+
!@uri.user.nil? || @options[:token]
|
632
774
|
end
|
633
775
|
|
634
776
|
def connect_command #:nodoc:
|
@@ -637,12 +779,19 @@ module NATS
|
|
637
779
|
:pedantic => @options[:pedantic],
|
638
780
|
:lang => ::NATS::LANG,
|
639
781
|
:version => ::NATS::VERSION,
|
640
|
-
:protocol => ::NATS::PROTOCOL_VERSION
|
782
|
+
:protocol => ::NATS::PROTOCOL_VERSION,
|
783
|
+
:echo => !@options[:no_echo]
|
641
784
|
}
|
642
|
-
|
785
|
+
case
|
786
|
+
when @options[:token]
|
787
|
+
cs[:auth_token] = @options[:token]
|
788
|
+
when @uri.password.nil?
|
789
|
+
cs[:auth_token] = @uri.user
|
790
|
+
else
|
643
791
|
cs[:user] = @uri.user
|
644
792
|
cs[:pass] = @uri.password
|
645
|
-
end
|
793
|
+
end if auth_connection?
|
794
|
+
|
646
795
|
cs[:name] = @options[:name] if @options[:name]
|
647
796
|
cs[:ssl_required] = @ssl if @ssl
|
648
797
|
cs[:tls_required] = true if @tls
|
@@ -701,6 +850,7 @@ module NATS
|
|
701
850
|
|
702
851
|
def receive_data(data) #:nodoc:
|
703
852
|
@buf = @buf ? @buf << data : data
|
853
|
+
|
704
854
|
while (@buf)
|
705
855
|
case @parse_state
|
706
856
|
when AWAITING_CONTROL_LINE
|
@@ -748,7 +898,6 @@ module NATS
|
|
748
898
|
@parse_state = AWAITING_CONTROL_LINE
|
749
899
|
@buf = nil if (@buf && @buf.empty?)
|
750
900
|
end
|
751
|
-
|
752
901
|
end
|
753
902
|
end
|
754
903
|
|
@@ -775,6 +924,14 @@ module NATS
|
|
775
924
|
# Otherwise, use a regular connection.
|
776
925
|
end
|
777
926
|
|
927
|
+
# Check whether there no echo is supported by the server.
|
928
|
+
if @options[:no_echo]
|
929
|
+
if @server_info[:proto].nil? || @server_info[:proto] < 1
|
930
|
+
err_cb.call(NATS::ServerError.new('No echo option not supported by this server'))
|
931
|
+
close_connection_after_writing
|
932
|
+
end
|
933
|
+
end
|
934
|
+
|
778
935
|
# Detect any announced server that we might not be aware of...
|
779
936
|
connect_urls = @server_info[:connect_urls]
|
780
937
|
if connect_urls
|
@@ -792,9 +949,9 @@ module NATS
|
|
792
949
|
u.password = options[:pass] if options[:pass]
|
793
950
|
|
794
951
|
# Use creds from the current server if not set explicitly.
|
795
|
-
if @uri
|
796
|
-
u.user ||= @uri.user
|
797
|
-
u.password ||= @uri.password
|
952
|
+
if @uri and !@uri.user.nil? and !@uri.user.empty?
|
953
|
+
u.user ||= @uri.user
|
954
|
+
u.password ||= @uri.password
|
798
955
|
end
|
799
956
|
|
800
957
|
srvs << { :uri => u, :reconnect_attempts => 0, :discovered => true }
|
data/lib/nats/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Collison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: eventmachine
|