nats 0.4.28 → 0.5.0.beta.12
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 +15 -0
- data/HISTORY.md +16 -0
- data/README.md +8 -5
- data/bin/nats-queue +14 -5
- data/bin/nats-request +12 -3
- data/bin/nats-sub +13 -5
- data/lib/nats/client.rb +189 -35
- data/lib/nats/server.rb +27 -4
- data/lib/nats/server/cluster.rb +102 -0
- data/lib/nats/server/connection.rb +47 -17
- data/lib/nats/server/connz.rb +0 -2
- data/lib/nats/server/const.rb +14 -2
- data/lib/nats/server/options.rb +19 -2
- data/lib/nats/server/route.rb +279 -0
- data/lib/nats/server/server.rb +35 -10
- data/lib/nats/server/varz.rb +1 -0
- data/nats.gemspec +6 -4
- metadata +38 -26
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTZjYWZjNDUxYmZmMzU2NTIxZjY0ODgwNTBlZWI4MGIwNTA1Y2U2NQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MjVkYjliNDVkMzNkNDA4ZjIxYjBhNjgxMzcxNDQ3MDQ5NzRiYjFjOA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ODFlNmMxMjkzMzgwYmIwM2I5NWMxNzE3YWY2ZjUxYzEwNDZiMzQyYWQ5M2Q5
|
10
|
+
MzQ2ZGUzYTZiYmU1NTBhZDczMmZjZjBhMzlhM2Q4ZDkzYzNhYjMzYmRlNzFk
|
11
|
+
Yzc2ZjUxNjEyNWUwZDQ3NzcxMDY0NGVmMzdlMDZlN2FlYzExMWQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
M2U4MTVjMmYyMzIxODI4NjZjZjhmNDkwOGE1MDM2ZWRmN2I4ZjJjMTYwMTQx
|
14
|
+
MWY0MTA2NmJhNzQ3ZWI3NGI1YmY4ODFmMzk2YzRmMzMwOWJjYjJlMGE3MDAy
|
15
|
+
N2EzNjM4MGZjOTQzOTgwMTYzNzk1YjY3ZTYzMTdjZTcyYmI0MDA=
|
data/HISTORY.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# HISTORY
|
2
2
|
|
3
|
+
## v0.5.0.beta.12 (October 1, 2013)
|
4
|
+
- Fixed issue #58, reconnects not stopped on auth failures
|
5
|
+
- Fixed leaking ping timers on auth failures
|
6
|
+
- Created AuthError
|
7
|
+
- See full list @ https://github.com/derekcollison/nats/compare/v0.5.0.beta.11...v0.5.0.beta.12
|
8
|
+
|
9
|
+
## v0.5.0.beta.11 (July 26, 2013)
|
10
|
+
- Bi-directional Route designation
|
11
|
+
- Upgrade to EM 1.x
|
12
|
+
- See full list @ https://github.com/derekcollison/nats/compare/v0.5.0.beta.1...v0.5.0.beta.11
|
13
|
+
|
14
|
+
## v0.5.0.beta.1 (Sept 10, 2012)
|
15
|
+
- Clustering support for nats-servers
|
16
|
+
- Reconnect client logic cluster aware (explicit servers only for now)
|
17
|
+
- See full list @ https://github.com/derekcollison/nats/compare/v0.4.26...v0.5.0.beta.1
|
18
|
+
|
3
19
|
## v0.4.28 (September 22, 2012)
|
4
20
|
- Binary payload bug fix
|
5
21
|
- Lock EM to version 0.12.10, 1.0 does not pass tests currently.
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
A lightweight publish-subscribe and distributed queueing messaging system.
|
4
4
|
|
5
|
-
[](http://travis-ci.org/derekcollison/nats)
|
5
|
+
[](http://travis-ci.org/derekcollison/nats)
|
6
6
|
|
7
7
|
## Supported Platforms
|
8
8
|
|
@@ -12,11 +12,14 @@ This gem currently works on the following Ruby platforms:
|
|
12
12
|
- Rubinius
|
13
13
|
- JRuby
|
14
14
|
|
15
|
+
## Additional Clients
|
16
|
+
|
15
17
|
There are several other client language bindings as well.
|
16
18
|
|
17
|
-
[Node.js](https://github.com/derekcollison/node_nats)
|
18
|
-
[Go
|
19
|
-
|
19
|
+
- [Node.js](https://github.com/derekcollison/node_nats)
|
20
|
+
- [Go](https://github.com/apcera/nats)
|
21
|
+
- [Java](https://github.com/tyagihas/java_nats)
|
22
|
+
- [Java - Spring](https://github.com/mheath/jnats)
|
20
23
|
|
21
24
|
## Getting Started
|
22
25
|
|
@@ -112,7 +115,7 @@ See examples and benchmarks for more information..
|
|
112
115
|
|
113
116
|
(The MIT License)
|
114
117
|
|
115
|
-
Copyright (c) 2010-
|
118
|
+
Copyright (c) 2010-2013 Derek Collison
|
116
119
|
|
117
120
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
118
121
|
of this software and associated documentation files (the "Software"), to
|
data/bin/nats-queue
CHANGED
@@ -7,14 +7,14 @@ require 'nats/client'
|
|
7
7
|
['TERM', 'INT'].each { |s| trap(s) { puts; exit! } }
|
8
8
|
|
9
9
|
def usage
|
10
|
-
puts "Usage: nats-queue <subject> <queue name> [-s server] [-t]"; exit
|
10
|
+
puts "Usage: nats-queue <subject> <queue name> [-s server] [-t] [-r]"; exit
|
11
11
|
end
|
12
12
|
|
13
13
|
args = ARGV.dup
|
14
14
|
opts_parser = OptionParser.new do |opts|
|
15
15
|
opts.on('-s SERVER') { |server| $nats_server = server }
|
16
|
-
opts.on('-t') { $show_time = true }
|
17
|
-
|
16
|
+
opts.on('-t','--time') { $show_time = true }
|
17
|
+
opts.on('-r','--raw') { $show_raw = true }
|
18
18
|
end
|
19
19
|
args = opts_parser.parse!(args)
|
20
20
|
|
@@ -30,11 +30,20 @@ def header
|
|
30
30
|
"#{time_prefix}[\##{$i+=1}]"
|
31
31
|
end
|
32
32
|
|
33
|
+
def decorate sub, msg
|
34
|
+
if $show_raw
|
35
|
+
msg
|
36
|
+
else
|
37
|
+
"#{header} Received on [#{sub}] : '#{msg}'"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
33
42
|
NATS.on_error { |err| puts "Server Error: #{err}"; exit! }
|
34
43
|
|
35
44
|
NATS.start(:uri => $nats_server, :autostart => true) do
|
36
|
-
puts "Listening on [#{subject}], queue group [#{queue_group}]"
|
45
|
+
puts "Listening on [#{subject}], queue group [#{queue_group}]" unless $show_raw
|
37
46
|
NATS.subscribe(subject, :queue => queue_group) { |msg, _, sub|
|
38
|
-
puts
|
47
|
+
puts decorate(sub, msg)
|
39
48
|
}
|
40
49
|
end
|
data/bin/nats-request
CHANGED
@@ -7,13 +7,14 @@ require 'nats/client'
|
|
7
7
|
['TERM', 'INT'].each { |s| trap(s) { puts; exit! } }
|
8
8
|
|
9
9
|
def usage
|
10
|
-
puts "Usage: nats-request <subject> <msg> [-s server] [-t] [-n responses]"; exit
|
10
|
+
puts "Usage: nats-request <subject> <msg> [-s server] [-t] [-r] [-n responses]"; exit
|
11
11
|
end
|
12
12
|
|
13
13
|
args = ARGV.dup
|
14
14
|
opts_parser = OptionParser.new do |opts|
|
15
15
|
opts.on('-s SERVER') { |server| $nats_server = server }
|
16
|
-
opts.on('-t') { $show_time = true }
|
16
|
+
opts.on('-t','--time') { $show_time = true }
|
17
|
+
opts.on('-r','--raw') { $show_raw = true }
|
17
18
|
opts.on('-n RESPONSES') { |responses| $responses = Integer(responses) if Integer(responses) > 0 }
|
18
19
|
end
|
19
20
|
args = opts_parser.parse!(args)
|
@@ -31,11 +32,19 @@ def header
|
|
31
32
|
"#{time_prefix}[\##{$i+=1}]"
|
32
33
|
end
|
33
34
|
|
35
|
+
def decorate msg
|
36
|
+
if $show_raw
|
37
|
+
msg
|
38
|
+
else
|
39
|
+
"#{header} Replied with : '#{msg}'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
34
43
|
NATS.on_error { |err| puts "Server Error: #{err}"; exit! }
|
35
44
|
|
36
45
|
NATS.start(:uri => $nats_server, :autostart => true) do
|
37
46
|
NATS.request(subject, msg) { |(msg, reply)|
|
38
|
-
puts
|
47
|
+
puts decorate(msg)
|
39
48
|
exit! if $responses && ($responses-=1) < 1
|
40
49
|
}
|
41
50
|
end
|
data/bin/nats-sub
CHANGED
@@ -7,14 +7,14 @@ require 'nats/client'
|
|
7
7
|
['TERM', 'INT'].each { |s| trap(s) { puts; exit! } }
|
8
8
|
|
9
9
|
def usage
|
10
|
-
puts "Usage: nats-sub <subject> [-s server] [-t]"; exit
|
10
|
+
puts "Usage: nats-sub <subject> [-s server] [-t] [-r]"; exit
|
11
11
|
end
|
12
12
|
|
13
13
|
args = ARGV.dup
|
14
14
|
opts_parser = OptionParser.new do |opts|
|
15
15
|
opts.on('-s SERVER') { |server| $nats_server = server }
|
16
|
-
opts.on('-t') { $show_time = true }
|
17
|
-
|
16
|
+
opts.on('-t','--time') { $show_time = true }
|
17
|
+
opts.on('-r','--raw') { $show_raw = true }
|
18
18
|
end
|
19
19
|
args = opts_parser.parse!(args)
|
20
20
|
|
@@ -30,9 +30,17 @@ def header
|
|
30
30
|
"#{time_prefix}[\##{$i+=1}]"
|
31
31
|
end
|
32
32
|
|
33
|
+
def decorate sub, msg
|
34
|
+
if $show_raw
|
35
|
+
msg
|
36
|
+
else
|
37
|
+
"#{header} Received on [#{sub}] : '#{msg}'"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
33
41
|
NATS.on_error { |err| puts "Server Error: #{err}"; exit! }
|
34
42
|
|
35
43
|
NATS.start(:uri => $nats_server, :autostart => true) do
|
36
|
-
puts "Listening on [#{subject}]"
|
37
|
-
NATS.subscribe(subject) { |msg, _, sub| puts
|
44
|
+
puts "Listening on [#{subject}]" unless $show_raw
|
45
|
+
NATS.subscribe(subject) { |msg, _, sub| puts decorate(sub, msg) }
|
38
46
|
end
|
data/lib/nats/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'securerandom'
|
2
3
|
|
3
4
|
ep = File.expand_path(File.dirname(__FILE__))
|
4
5
|
|
@@ -8,7 +9,7 @@ require "#{ep}/ext/json"
|
|
8
9
|
|
9
10
|
module NATS
|
10
11
|
|
11
|
-
VERSION =
|
12
|
+
VERSION = "0.5.0.beta.12".freeze
|
12
13
|
|
13
14
|
DEFAULT_PORT = 4222
|
14
15
|
DEFAULT_URI = "nats://localhost:#{DEFAULT_PORT}".freeze
|
@@ -21,6 +22,10 @@ module NATS
|
|
21
22
|
# Maximum outbound size per client to trigger FP, 20MB
|
22
23
|
FAST_PRODUCER_THRESHOLD = (10*1024*1024)
|
23
24
|
|
25
|
+
# Ping intervals
|
26
|
+
DEFAULT_PING_INTERVAL = 120
|
27
|
+
DEFAULT_PING_MAX = 2
|
28
|
+
|
24
29
|
# Protocol
|
25
30
|
# @private
|
26
31
|
MSG = /\AMSG\s+([^\s]+)\s+([^\s]+)\s+(([^\s]+)[^\S\r\n]+)?(\d+)\r\n/i #:nodoc:
|
@@ -66,6 +71,9 @@ module NATS
|
|
66
71
|
# When we cannot connect to the server (either initially or after a reconnect), this is raised/passed
|
67
72
|
class ConnectError < Error; end #:nodoc:
|
68
73
|
|
74
|
+
# When we cannot connect to the server because authorization failed.
|
75
|
+
class AuthError < ConnectError; end #:nodoc:
|
76
|
+
|
69
77
|
class << self
|
70
78
|
attr_reader :client, :reactor_was_running, :err_cb, :err_cb_overridden #:nodoc:
|
71
79
|
attr_reader :reconnect_cb #:nodoc
|
@@ -87,6 +95,8 @@ module NATS
|
|
87
95
|
# @option opts [Boolean] :ssl Boolean that is sent to server for setting TLS/SSL mode.
|
88
96
|
# @option opts [Integer] :max_reconnect_attempts Integer that can be used to set the max number of reconnect tries
|
89
97
|
# @option opts [Integer] :reconnect_time_wait Integer that can be used to set the number of seconds to wait between reconnect tries
|
98
|
+
# @option opts [Integer] :ping_interval Integer that can be used to set the ping interval in seconds.
|
99
|
+
# @option opts [Integer] :max_outstanding_pings Integer that can be used to set the max number of outstanding pings before declaring a connection closed.
|
90
100
|
# @param [Block] &blk called when the connection is completed. Connection will be passed to the block.
|
91
101
|
# @return [NATS] connection to the server.
|
92
102
|
def connect(opts={}, &blk)
|
@@ -97,6 +107,8 @@ module NATS
|
|
97
107
|
opts[:ssl] = false if opts[:ssl].nil?
|
98
108
|
opts[:max_reconnect_attempts] = MAX_RECONNECT_ATTEMPTS if opts[:max_reconnect_attempts].nil?
|
99
109
|
opts[:reconnect_time_wait] = RECONNECT_TIME_WAIT if opts[:reconnect_time_wait].nil?
|
110
|
+
opts[:ping_interval] = DEFAULT_PING_INTERVAL if opts[:ping_interval].nil?
|
111
|
+
opts[:max_outstanding_pings] = DEFAULT_PING_MAX if opts[:max_outstanding_pings].nil?
|
100
112
|
|
101
113
|
# Override with ENV
|
102
114
|
opts[:uri] ||= ENV['NATS_URI'] || DEFAULT_URI
|
@@ -108,7 +120,19 @@ module NATS
|
|
108
120
|
opts[:ssl] = ENV['NATS_SSL'].downcase == 'true' unless ENV['NATS_SSL'].nil?
|
109
121
|
opts[:max_reconnect_attempts] = ENV['NATS_MAX_RECONNECT_ATTEMPTS'].to_i unless ENV['NATS_MAX_RECONNECT_ATTEMPTS'].nil?
|
110
122
|
opts[:reconnect_time_wait] = ENV['NATS_RECONNECT_TIME_WAIT'].to_i unless ENV['NATS_RECONNECT_TIME_WAIT'].nil?
|
111
|
-
|
123
|
+
|
124
|
+
opts[:ping_interval] = ENV['NATS_PING_INTERVAL'].to_i unless ENV['NATS_PING_INTERVAL'].nil?
|
125
|
+
opts[:max_outstanding_pings] = ENV['NATS_MAX_OUTSTANDING_PINGS'].to_i unless ENV['NATS_MAX_OUTSTANDING_PINGS'].nil?
|
126
|
+
|
127
|
+
uri = opts[:uris] || opts[:servers] || opts[:uri]
|
128
|
+
|
129
|
+
# If they pass an array here just pass along to the real connection, and use first as the first attempt..
|
130
|
+
# Real connection will do proper walk throughs etc..
|
131
|
+
unless uri.nil?
|
132
|
+
u = uri.kind_of?(Array) ? uri.first : uri
|
133
|
+
@uri = u.is_a?(URI) ? u.dup : URI.parse(u)
|
134
|
+
end
|
135
|
+
|
112
136
|
@err_cb = proc { |e| raise e } unless err_cb
|
113
137
|
check_autostart(@uri) if opts[:autostart] == true
|
114
138
|
|
@@ -122,7 +146,7 @@ module NATS
|
|
122
146
|
def start(*args, &blk)
|
123
147
|
@reactor_was_running = EM.reactor_running?
|
124
148
|
unless (@reactor_was_running || blk)
|
125
|
-
raise(Error, "EM needs to be running when NATS.start called without a run block")
|
149
|
+
raise(Error, "EM needs to be running when NATS.start is called without a run block")
|
126
150
|
end
|
127
151
|
# Setup optimized select versions
|
128
152
|
EM.epoll; EM.kqueue
|
@@ -172,6 +196,7 @@ module NATS
|
|
172
196
|
# @param [Block] &callback called when a reconnect attempt is made.
|
173
197
|
def on_reconnect(&callback)
|
174
198
|
@reconnect_cb = callback
|
199
|
+
@client.on_reconnect(&callback) unless @client.nil?
|
175
200
|
end
|
176
201
|
|
177
202
|
# Publish a message using the default client connection.
|
@@ -207,9 +232,7 @@ module NATS
|
|
207
232
|
# Returns a subject that can be used for "directed" communications.
|
208
233
|
# @return [String]
|
209
234
|
def create_inbox
|
210
|
-
|
211
|
-
rand(0x0010000),rand(0x0010000),rand(0x1000000)]
|
212
|
-
"_INBOX.%04x%04x%04x%04x%04x%06x" % v
|
235
|
+
"_INBOX.#{SecureRandom.hex(13)}"
|
213
236
|
end
|
214
237
|
|
215
238
|
# Flushes all messages and subscriptions in the default connection
|
@@ -272,8 +295,8 @@ module NATS
|
|
272
295
|
|
273
296
|
end
|
274
297
|
|
275
|
-
attr_reader :connected, :connect_cb, :err_cb, :err_cb_overridden #:nodoc:
|
276
|
-
attr_reader :closing, :reconnecting, :options, :server_info #:nodoc
|
298
|
+
attr_reader :connected, :connect_cb, :err_cb, :err_cb_overridden, :pongs_received #:nodoc:
|
299
|
+
attr_reader :closing, :reconnecting, :server_pool, :options, :server_info #:nodoc
|
277
300
|
attr_reader :msgs_received, :msgs_sent, :bytes_received, :bytes_sent, :pings
|
278
301
|
|
279
302
|
alias :connected? :connected
|
@@ -281,16 +304,14 @@ module NATS
|
|
281
304
|
alias :reconnecting? :reconnecting
|
282
305
|
|
283
306
|
def initialize(options)
|
284
|
-
@uri = options[:uri]
|
285
|
-
@uri.user = options[:user] if options[:user]
|
286
|
-
@uri.password = options[:pass] if options[:pass]
|
287
|
-
@ssl = options[:ssl] if options[:ssl]
|
288
307
|
@options = options
|
308
|
+
process_uri_options
|
309
|
+
@ssl = options[:ssl] if options[:ssl]
|
289
310
|
@ssid, @subs = 1, {}
|
290
311
|
@err_cb = NATS.err_cb
|
291
312
|
@reconnect_timer, @needed = nil, nil
|
292
313
|
@reconnect_cb = NATS.reconnect_cb
|
293
|
-
@connected, @closing, @reconnecting = false, false, false
|
314
|
+
@connected, @closing, @reconnecting, @conn_cb_called = false, false, false, false
|
294
315
|
@msgs_received = @msgs_sent = @bytes_received = @bytes_sent = @pings = 0
|
295
316
|
@pending_size = 0
|
296
317
|
send_connect_command
|
@@ -418,7 +439,8 @@ module NATS
|
|
418
439
|
# Close the connection to the server.
|
419
440
|
def close
|
420
441
|
@closing = true
|
421
|
-
|
442
|
+
cancel_ping_timer
|
443
|
+
cancel_reconnect_timer
|
422
444
|
close_connection_after_writing if connected?
|
423
445
|
process_disconnect if reconnecting?
|
424
446
|
end
|
@@ -432,14 +454,22 @@ module NATS
|
|
432
454
|
err_cb_overridden || NATS.err_cb_overridden
|
433
455
|
end
|
434
456
|
|
435
|
-
def
|
457
|
+
def auth_connection?
|
458
|
+
!@uri.user.nil?
|
459
|
+
end
|
460
|
+
|
461
|
+
def connect_command #:nodoc:
|
436
462
|
cs = { :verbose => @options[:verbose], :pedantic => @options[:pedantic] }
|
437
|
-
if
|
463
|
+
if auth_connection?
|
438
464
|
cs[:user] = @uri.user
|
439
465
|
cs[:pass] = @uri.password
|
440
466
|
end
|
441
467
|
cs[:ssl_required] = @ssl if @ssl
|
442
|
-
|
468
|
+
"CONNECT #{cs.to_json}#{CR_LF}"
|
469
|
+
end
|
470
|
+
|
471
|
+
def send_connect_command #:nodoc:
|
472
|
+
send_command(connect_command, true)
|
443
473
|
end
|
444
474
|
|
445
475
|
def queue_server_rt(&cb) #:nodoc:
|
@@ -465,8 +495,6 @@ module NATS
|
|
465
495
|
@subs.delete(sid) if (sub[:received] == sub[:max])
|
466
496
|
end
|
467
497
|
|
468
|
-
return unsubscribe(sid) if (sub[:max] && (sub[:received] > sub[:max]))
|
469
|
-
|
470
498
|
if cb = sub[:callback]
|
471
499
|
case cb.arity
|
472
500
|
when 0 then cb.call
|
@@ -503,7 +531,13 @@ module NATS
|
|
503
531
|
@buf = $'
|
504
532
|
when ERR
|
505
533
|
@buf = $'
|
506
|
-
|
534
|
+
current = server_pool.first
|
535
|
+
current[:error_received] = true
|
536
|
+
if current[:auth_required] && !current[:auth_ok]
|
537
|
+
err_cb.call(NATS::AuthError.new($1))
|
538
|
+
else
|
539
|
+
err_cb.call(NATS::ServerError.new($1))
|
540
|
+
end
|
507
541
|
when PING
|
508
542
|
@pings += 1
|
509
543
|
@buf = $'
|
@@ -547,6 +581,12 @@ module NATS
|
|
547
581
|
err_cb.call(NATS::ClientError.new('TLS/SSL not supported by server'))
|
548
582
|
end
|
549
583
|
end
|
584
|
+
if @server_info[:auth_required]
|
585
|
+
current = server_pool.first
|
586
|
+
current[:auth_required] = true
|
587
|
+
queue_server_rt { current[:auth_ok] = true }
|
588
|
+
flush_pending
|
589
|
+
end
|
550
590
|
@server_info
|
551
591
|
end
|
552
592
|
|
@@ -555,38 +595,103 @@ module NATS
|
|
555
595
|
flush_pending
|
556
596
|
end
|
557
597
|
|
598
|
+
def cancel_ping_timer
|
599
|
+
if @ping_timer
|
600
|
+
EM.cancel_timer(@ping_timer)
|
601
|
+
@ping_timer = nil
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
558
605
|
def connection_completed #:nodoc:
|
559
606
|
@connected = true unless @ssl
|
607
|
+
|
608
|
+
current = server_pool.first
|
609
|
+
current[:was_connected] = true
|
610
|
+
current[:reconnect_attempts] = 0
|
611
|
+
|
560
612
|
if reconnecting?
|
561
|
-
|
562
|
-
send_connect_command
|
613
|
+
cancel_reconnect_timer
|
563
614
|
@subs.each_pair { |k, v| send_command("SUB #{v[:subject]} #{v[:queue]} #{k}#{CR_LF}") }
|
564
615
|
end
|
565
|
-
|
616
|
+
|
566
617
|
unless user_err_cb? or reconnecting?
|
567
618
|
@err_cb = proc { |e| raise e }
|
568
619
|
end
|
569
|
-
|
620
|
+
|
621
|
+
flush_pending unless @ssl
|
622
|
+
|
623
|
+
if (connect_cb and not @conn_cb_called)
|
570
624
|
# We will round trip the server here to make sure all state from any pending commands
|
571
625
|
# has been processed before calling the connect callback.
|
572
|
-
queue_server_rt
|
626
|
+
queue_server_rt do
|
627
|
+
connect_cb.call(self)
|
628
|
+
@conn_cb_called = true
|
629
|
+
end
|
573
630
|
end
|
574
631
|
@reconnecting = false
|
575
632
|
@parse_state = AWAITING_CONTROL_LINE
|
633
|
+
|
634
|
+
# Initialize ping timer and processing
|
635
|
+
@pings_outstanding = 0
|
636
|
+
@pongs_received = 0
|
637
|
+
@ping_timer = EM.add_periodic_timer(@options[:ping_interval]) { send_ping }
|
638
|
+
end
|
639
|
+
|
640
|
+
def send_ping #:nodoc:
|
641
|
+
return if @closing
|
642
|
+
if @pings_outstanding > @options[:max_outstanding_pings]
|
643
|
+
close_connection
|
644
|
+
#close
|
645
|
+
return
|
646
|
+
end
|
647
|
+
@pings_outstanding += 1
|
648
|
+
queue_server_rt { process_pong }
|
649
|
+
flush_pending
|
650
|
+
end
|
651
|
+
|
652
|
+
def process_pong
|
653
|
+
@pongs_received += 1
|
654
|
+
@pings_outstanding -= 1
|
655
|
+
end
|
656
|
+
|
657
|
+
def should_delay_connect?(server)
|
658
|
+
server[:was_connected] && server[:reconnect_attempts] >= 1
|
576
659
|
end
|
577
660
|
|
578
|
-
def schedule_reconnect
|
661
|
+
def schedule_reconnect #:nodoc:
|
579
662
|
@reconnecting = true
|
580
|
-
@reconnect_attempts = 0
|
581
663
|
@connected = false
|
582
|
-
@reconnect_timer = EM.
|
664
|
+
@reconnect_timer = EM.add_timer(@options[:reconnect_time_wait]) { attempt_reconnect }
|
583
665
|
end
|
584
666
|
|
585
667
|
def unbind #:nodoc:
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
668
|
+
# If we are closing or shouldn't reconnect, go ahead and disconnect.
|
669
|
+
process_disconnect and return if (closing? or should_not_reconnect?)
|
670
|
+
|
671
|
+
@reconnecting = true if connected?
|
672
|
+
@connected = false
|
673
|
+
@pending = @pongs = nil
|
674
|
+
cancel_ping_timer
|
675
|
+
|
676
|
+
schedule_primary_and_connect
|
677
|
+
end
|
678
|
+
|
679
|
+
def multiple_servers_available?
|
680
|
+
server_pool && server_pool.size > 1
|
681
|
+
end
|
682
|
+
|
683
|
+
def had_error?
|
684
|
+
server_pool.first && server_pool.first[:error_received]
|
685
|
+
end
|
686
|
+
|
687
|
+
def should_not_reconnect?
|
688
|
+
!@options[:reconnect]
|
689
|
+
end
|
690
|
+
|
691
|
+
def cancel_reconnect_timer
|
692
|
+
if @reconnect_timer
|
693
|
+
EM.cancel_timer(@reconnect_timer)
|
694
|
+
@reconnect_timer = nil
|
590
695
|
end
|
591
696
|
end
|
592
697
|
|
@@ -597,18 +702,26 @@ module NATS
|
|
597
702
|
|
598
703
|
def process_disconnect #:nodoc:
|
599
704
|
err_cb.call(NATS::ConnectError.new(disconnect_error_string)) if not closing? and @err_cb
|
705
|
+
true # Chaining
|
600
706
|
ensure
|
601
|
-
|
707
|
+
cancel_ping_timer
|
708
|
+
cancel_reconnect_timer
|
602
709
|
if (NATS.client == self)
|
603
710
|
NATS.clear_client
|
604
711
|
EM.stop if ((connected? || reconnecting?) and closing? and not NATS.reactor_was_running?)
|
605
712
|
end
|
606
713
|
@connected = @reconnecting = false
|
607
|
-
|
714
|
+
end
|
715
|
+
|
716
|
+
def can_reuse_server?(server) #:nodoc:
|
717
|
+
reconnecting? && server[:was_connected] && server[:reconnect_attempts] <= @options[:max_reconnect_attempts]
|
608
718
|
end
|
609
719
|
|
610
720
|
def attempt_reconnect #:nodoc:
|
611
|
-
|
721
|
+
@reconnect_timer = nil
|
722
|
+
current = server_pool.first
|
723
|
+
current[:reconnect_attempts] += 1 if current[:reconnect_attempts]
|
724
|
+
send_connect_command
|
612
725
|
EM.reconnect(@uri.host, @uri.port, self)
|
613
726
|
@reconnect_cb.call unless @reconnect_cb.nil?
|
614
727
|
end
|
@@ -626,6 +739,47 @@ module NATS
|
|
626
739
|
true
|
627
740
|
end
|
628
741
|
|
742
|
+
# Parse out URIs which can now be an array of server choices
|
743
|
+
# The server pool will contain both explicit and implicit members.
|
744
|
+
def process_uri_options #:nodoc
|
745
|
+
@server_pool = []
|
746
|
+
uri = options[:uris] || options[:servers] || options[:uri]
|
747
|
+
uri = uri.kind_of?(Array) ? uri : [uri]
|
748
|
+
uri.each { |u| server_pool << { :uri => u.is_a?(URI) ? u.dup : URI.parse(u) } }
|
749
|
+
server_pool.shuffle! unless options[:dont_randomize_servers]
|
750
|
+
bind_primary
|
751
|
+
end
|
752
|
+
|
753
|
+
def connected_server
|
754
|
+
connected? ? @uri : nil
|
755
|
+
end
|
756
|
+
|
757
|
+
def bind_primary #:nodoc:
|
758
|
+
first = server_pool.first
|
759
|
+
@uri = first[:uri]
|
760
|
+
@uri.user = options[:user] if options[:user]
|
761
|
+
@uri.password = options[:pass] if options[:pass]
|
762
|
+
first
|
763
|
+
end
|
764
|
+
|
765
|
+
# We have failed on an attempt at the primary (first) server, rotate and try again
|
766
|
+
def schedule_primary_and_connect #:nodoc:
|
767
|
+
# Dump the one we were trying if it wasn't connected
|
768
|
+
current = server_pool.shift
|
769
|
+
server_pool << current if (current && can_reuse_server?(current) && !current[:error_received])
|
770
|
+
# If we are out of options, go ahead and disconnect.
|
771
|
+
process_disconnect and return if server_pool.empty?
|
772
|
+
# bind new one
|
773
|
+
next_server = bind_primary
|
774
|
+
# If the next one was connected and we are trying to reconnect
|
775
|
+
# set up timer if we tried once already.
|
776
|
+
if should_delay_connect?(next_server)
|
777
|
+
schedule_reconnect
|
778
|
+
else
|
779
|
+
attempt_reconnect
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
629
783
|
def inspect #:nodoc:
|
630
784
|
"<nats client v#{NATS::VERSION}>"
|
631
785
|
end
|