nats 0.4.28 → 0.5.0.beta.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://secure.travis-ci.org/derekcollison/nats.png)](http://travis-ci.org/derekcollison/nats)
|
5
|
+
[![Build Status](https://secure.travis-ci.org/derekcollison/nats.png?branch=cluster)](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
|