nats 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![License Apache 2.0](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
|
6
|
-
[![Build Status](https://travis-ci.org/nats-io/ruby-nats.svg)](http://travis-ci.org/nats-io/ruby-nats) [![Gem Version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=rb&type=5&v=0.
|
6
|
+
[![Build Status](https://travis-ci.org/nats-io/ruby-nats.svg)](http://travis-ci.org/nats-io/ruby-nats) [![Gem Version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=rb&type=5&v=0.10.0)](https://rubygems.org/gems/nats/versions/0.10.0) [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](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
|