nats 0.6.0 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9001307af28148c669590f0964512c8ddc60cff4
4
- data.tar.gz: 97ffb35dca621454dddcda8aad90d081b7d51520
3
+ metadata.gz: a79cc55bf741a649b4ee2ae245b57c15bbc65bd1
4
+ data.tar.gz: 2ab66dfaa047037ae06543de3e398154e0bd81f2
5
5
  SHA512:
6
- metadata.gz: a2aaddd687461480f22bd596d60d1b28cf10af716d011d2531e9e7f31f6b5391c9e67f33f494378c8d39c7973ae426bce6e93227e8ce65ec30d3988d045f02f1
7
- data.tar.gz: 446229594e7a0f4aa88aba27e5e3f12abe8adffdde363674a7e464ed541567ed81370ef939a25c77d455051407078fd6dce73f89d310bb5e0bd5637c7e2b5032
6
+ metadata.gz: 7bebf05b5735ee2c65de1ca58298ab5626f90ec31e2e743a7b90ac0d6a3243d379a04926c630aa6e8dd63ce133f5a6a1624448142ff762d5ad8e787e4afde43c
7
+ data.tar.gz: 9ab82b046d006ee3aab898577fb439568d142157ecaba641a12903fd8ed9c65022d850e10a02ebc50558486fa33a0cd1c98bfbed200a7cfc5bedee6132fe4b24
data/README.md CHANGED
@@ -3,24 +3,20 @@
3
3
  A [Ruby](http://ruby-lang.org) client for the [NATS messaging system](https://nats.io).
4
4
 
5
5
  [![License MIT](https://img.shields.io/npm/l/express.svg)](http://opensource.org/licenses/MIT)
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.5.0)](https://rubygems.org/gems/nats/versions/0.5.0) [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/nats-io/ruby-nats)
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.7.0)](https://rubygems.org/gems/nats/versions/0.7.0) [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/nats-io/ruby-nats)
7
7
 
8
8
 
9
9
  ## Supported Platforms
10
10
 
11
11
  This gem and the client are known to work on the following Ruby platforms:
12
12
 
13
- - MRI 1.9, 2.0, 2.1
13
+ - MRI 1.9, 2.0, 2.1, 2.2, 2.3.0
14
14
  - JRuby 1.6.8 (experimental)
15
15
 
16
- Note: This installation installs a version of the NATS server written in Ruby that has been deprecated. Please utilize a supported server such as [gnatsd](https://github.com/apcera/gnatsd). nats-server will be removed in a future release.
17
-
18
16
  ## Getting Started
19
17
 
20
18
  ```bash
21
- [sudo] gem install nats
22
- == or ==
23
- [sudo] rake geminstall
19
+ gem install nats
24
20
 
25
21
  nats-sub foo &
26
22
  nats-pub foo 'Hello World!'
@@ -79,11 +75,21 @@ NATS.subscribe(subject, :queue => 'job.workers') { |msg| puts "Received '#{msg}'
79
75
  ```
80
76
 
81
77
  ## Clustered Usage
78
+
82
79
  ```ruby
83
- NATS.start(:servers => ['nats://127.0.0.1:4222', 'nats://127.0.0.1:4223'] do |c|
84
- puts "NATS is connected to #{c.connected_server}"
85
- c.on_reconnect do
86
- puts "Reconnected to server at #{c.connected_server}"
80
+ NATS.start(:servers => ['nats://127.0.0.1:4222', 'nats://127.0.0.1:4223']) do |nc|
81
+ puts "NATS is connected to #{nc.connected_server}"
82
+
83
+ nc.on_reconnect do
84
+ puts "Reconnected to server at #{nc.connected_server}"
85
+ end
86
+
87
+ nc.on_disconnect do |reason|
88
+ puts "Disconnected: #{reason}"
89
+ end
90
+
91
+ nc.on_close do
92
+ puts "Connection to NATS closed"
87
93
  end
88
94
  end
89
95
 
@@ -101,6 +107,7 @@ end
101
107
  ```
102
108
 
103
109
  ## Advanced Usage
110
+
104
111
  ```ruby
105
112
  # Publish with closure, callback fires when server has processed the message
106
113
  NATS.publish('foo', 'You done?') { puts 'msg processed!' }
@@ -117,21 +124,74 @@ NATS.unsubscribe(sid, MAX_WANTED)
117
124
 
118
125
  # Multiple connections
119
126
  NATS.subscribe('test') do |msg|
120
- puts "received msg"
121
- NATS.stop
127
+ puts "received msg"
128
+ NATS.stop
122
129
  end
123
130
 
124
131
  # Form second connection to send message on
125
132
  NATS.connect { NATS.publish('test', 'Hello World!') }
126
133
  ```
127
134
 
135
+ ### TLS
136
+
137
+ Advanced customizations options for setting up a secure connection can be done by including them on connect:
138
+
139
+ ```ruby
140
+ options = {
141
+ :servers => [
142
+ 'nats://secret:deadbeef@127.0.0.1:4443',
143
+ 'nats://secret:deadbeef@127.0.0.1:4444'
144
+ ],
145
+ :max_reconnect_attempts => 10,
146
+ :reconnect_time_wait => 2,
147
+ :tls => {
148
+ :private_key_file => './spec/configs/certs/key.pem',
149
+ :cert_chain_file => './spec/configs/certs/server.pem'
150
+ # Can enable verify_peer functionality optionally by passing
151
+ # the location of a ca_file.
152
+ # :verify_peer => true,
153
+ # :ca_file => './spec/configs/certs/ca.pem'
154
+ }
155
+ }
156
+
157
+ # Set default callbacks
158
+ NATS.on_error do |e|
159
+ puts "Error: #{e}"
160
+ end
161
+
162
+ NATS.on_disconnect do |reason|
163
+ puts "Disconnected: #{reason}"
164
+ end
165
+
166
+ NATS.on_reconnect do |nats|
167
+ puts "Reconnected to NATS server at #{nats.connected_server}"
168
+ end
169
+
170
+ NATS.on_close do
171
+ puts "Connection to NATS closed"
172
+ EM.stop
173
+ end
174
+
175
+ NATS.start(options) do |nats|
176
+ puts "Connected to NATS at #{nats.connected_server}"
177
+
178
+ nats.subscribe("hello") do |msg|
179
+ puts "Received: #{msg}"
180
+ end
181
+
182
+ nats.flush do
183
+ nats.publish("hello", "world")
184
+ end
185
+ end
186
+ ```
187
+
128
188
  See examples and benchmarks for more information..
129
189
 
130
190
  ## License
131
191
 
132
192
  (The MIT License)
133
193
 
134
- Copyright (c) 2010-2015 Derek Collison
194
+ Copyright (c) 2010-2016 Derek Collison
135
195
 
136
196
  Permission is hereby granted, free of charge, to any person obtaining a copy
137
197
  of this software and associated documentation files (the "Software"), to
data/lib/nats/client.rb CHANGED
@@ -58,7 +58,7 @@ module NATS
58
58
  # When the NATS server sends us an ERROR message, this is raised/passed by default
59
59
  class ServerError < Error; end #:nodoc:
60
60
 
61
- # When we detect error on the client side (e.g. Fast Producer)
61
+ # When we detect error on the client side (e.g. Fast Producer, TLS required)
62
62
  class ClientError < Error; end #:nodoc:
63
63
 
64
64
  # When we cannot connect to the server (either initially or after a reconnect), this is raised/passed
@@ -69,8 +69,7 @@ module NATS
69
69
 
70
70
  class << self
71
71
  attr_reader :client, :reactor_was_running, :err_cb, :err_cb_overridden #:nodoc:
72
- attr_reader :reconnect_cb #:nodoc
73
- attr_accessor :timeout_cb #:nodoc
72
+ attr_reader :reconnect_cb, :close_cb, :disconnect_cb #:nodoc
74
73
 
75
74
  alias :reactor_was_running? :reactor_was_running
76
75
 
@@ -84,6 +83,7 @@ module NATS
84
83
  # @option opts [Boolean] :verbose Boolean that is sent to server for setting verbose protocol mode.
85
84
  # @option opts [Boolean] :pedantic Boolean that is sent to server for setting pedantic mode.
86
85
  # @option opts [Boolean] :ssl Boolean that is sent to server for setting TLS/SSL mode.
86
+ # @option opts [Hash] :tls Map of options for configuring secure connection handled to EM#start_tls directly.
87
87
  # @option opts [Integer] :max_reconnect_attempts Integer that can be used to set the max number of reconnect tries
88
88
  # @option opts [Integer] :reconnect_time_wait Integer that can be used to set the number of seconds to wait between reconnect tries
89
89
  # @option opts [Integer] :ping_interval Integer that can be used to set the ping interval in seconds.
@@ -117,6 +117,32 @@ module NATS
117
117
 
118
118
  uri = opts[:uris] || opts[:servers] || opts[:uri]
119
119
 
120
+ if opts[:tls]
121
+ case
122
+ when opts[:tls][:ca_file]
123
+ # Ensure that the file exists before going further
124
+ # in order to report configuration errors during
125
+ # connect synchronously.
126
+ if !File.readable?(opts[:tls][:ca_file])
127
+ raise(Error, "TLS Verification is enabled but ca_file %s is not readable" % opts[:tls][:ca_file])
128
+ end
129
+
130
+ # Certificate is supplied so assume we mean verification by default,
131
+ # but still allow disabling explicitly by setting to false.
132
+ opts[:tls][:verify_peer] ||= true
133
+ when (opts[:tls][:verify_peer] && !opts[:tls][:ca_file])
134
+ raise(Error, "TLS Verification is enabled but ca_file is not set")
135
+ else
136
+ # Otherwise, disable verifying peer by default,
137
+ # thus never reaching EM#ssl_verify_peer
138
+ opts[:tls][:verify_peer] = false
139
+ end
140
+
141
+ # Allow overriding directly but default to those which server supports.
142
+ opts[:tls][:ssl_version] ||= %w(tlsv1 tlsv1_1 tlsv1_2)
143
+ opts[:tls][:protocols] ||= %w(tlsv1 tlsv1_1 tlsv1_2)
144
+ end
145
+
120
146
  # If they pass an array here just pass along to the real connection, and use first as the first attempt..
121
147
  # Real connection will do proper walk throughs etc..
122
148
  unless uri.nil?
@@ -127,6 +153,8 @@ module NATS
127
153
  end
128
154
 
129
155
  @err_cb = proc { |e| raise e } unless err_cb
156
+ @close_cb = proc { } unless close_cb
157
+ @disconnect_cb = proc { } unless disconnect_cb
130
158
 
131
159
  client = EM.connect(@uri.host, @uri.port, self, opts)
132
160
  client.on_connect(&blk) if blk
@@ -157,6 +185,9 @@ module NATS
157
185
  client.close if (client and (client.connected? || client.reconnecting?))
158
186
  blk.call if blk
159
187
  @err_cb = nil
188
+ @close_cb = nil
189
+ @reconnect_cb = nil
190
+ @disconnect_cb = nil
160
191
  end
161
192
 
162
193
  # @return [URI] Connected server
@@ -202,6 +233,20 @@ module NATS
202
233
  @client.on_reconnect(&callback) unless @client.nil?
203
234
  end
204
235
 
236
+ # Set the default on_disconnect callback.
237
+ # @param [Block] &callback called whenever client disconnects from a server.
238
+ def on_disconnect(&callback)
239
+ @disconnect_cb = callback
240
+ @client.on_disconnect(&callback) unless @client.nil?
241
+ end
242
+
243
+ # Set the default on_closed callback.
244
+ # @param [Block] &callback called when will reach a state when will no longer be connected.
245
+ def on_close(&callback)
246
+ @close_cb = callback
247
+ @client.on_close(&callback) unless @client.nil?
248
+ end
249
+
205
250
  # Publish a message using the default client connection.
206
251
  # @see NATS#publish
207
252
  def publish(*args, &blk)
@@ -282,6 +327,7 @@ module NATS
282
327
  attr_reader :connected, :connect_cb, :err_cb, :err_cb_overridden, :pongs_received #:nodoc:
283
328
  attr_reader :closing, :reconnecting, :server_pool, :options, :server_info #:nodoc
284
329
  attr_reader :msgs_received, :msgs_sent, :bytes_received, :bytes_sent, :pings
330
+ attr_reader :disconnect_cb, :close_cb
285
331
 
286
332
  alias :connected? :connected
287
333
  alias :closing? :closing
@@ -290,16 +336,26 @@ module NATS
290
336
  def initialize(options)
291
337
  @options = options
292
338
  process_uri_options
293
- @ssl = false
294
- @ssl = options[:ssl] if options[:ssl]
339
+
295
340
  @buf = nil
296
341
  @ssid, @subs = 1, {}
297
342
  @err_cb = NATS.err_cb
298
- @reconnect_timer, @needed = nil, nil
343
+ @close_cb = NATS.close_cb
299
344
  @reconnect_cb = NATS.reconnect_cb
345
+ @disconnect_cb = NATS.disconnect_cb
346
+ @reconnect_timer, @needed = nil, nil
300
347
  @connected, @closing, @reconnecting, @conn_cb_called = false, false, false, false
301
348
  @msgs_received = @msgs_sent = @bytes_received = @bytes_sent = @pings = 0
302
349
  @pending_size = 0
350
+ @server_info = { }
351
+
352
+ # Mark whether we should be connecting securely, try best effort
353
+ # in being compatible with present ssl support.
354
+ @ssl = false
355
+ @tls = nil
356
+ @tls = options[:tls] if options[:tls]
357
+ @ssl = options[:ssl] if options[:ssl] or @tls
358
+
303
359
  send_connect_command
304
360
  end
305
361
 
@@ -411,17 +467,29 @@ module NATS
411
467
  end
412
468
 
413
469
  # Define a callback to be called when errors occur on the client connection.
414
- # @param [Block] &blk called when the connection is closed.
470
+ # @param [Block] &callback called when an error has been detected.
415
471
  def on_error(&callback)
416
472
  @err_cb, @err_cb_overridden = callback, true
417
473
  end
418
474
 
419
475
  # Define a callback to be called when a reconnect attempt is made.
420
- # @param [Block] &blk called when the connection is closed.
476
+ # @param [Block] &callback called when a reconnect attempt is made.
421
477
  def on_reconnect(&callback)
422
478
  @reconnect_cb = callback
423
479
  end
424
480
 
481
+ # Define a callback to be called when client is disconnected from server.
482
+ # @param [Block] &callback called whenever client disconnects from a server.
483
+ def on_disconnect(&callback)
484
+ @disconnect_cb = callback
485
+ end
486
+
487
+ # Define a callback to be called when client is disconnected from server.
488
+ # @param [Block] &callback called when will reach a state when will no longer be connected.
489
+ def on_close(&callback)
490
+ @close_cb = callback
491
+ end
492
+
425
493
  # Close the connection to the server.
426
494
  def close
427
495
  @closing = true
@@ -448,7 +516,7 @@ module NATS
448
516
  cs = {
449
517
  :verbose => @options[:verbose],
450
518
  :pedantic => @options[:pedantic],
451
- :lang => "ruby",
519
+ :lang => :ruby,
452
520
  :version => VERSION
453
521
  }
454
522
  if auth_connection?
@@ -456,6 +524,8 @@ module NATS
456
524
  cs[:pass] = @uri.password
457
525
  end
458
526
  cs[:ssl_required] = @ssl if @ssl
527
+ cs[:tls_required] = true if @tls
528
+
459
529
  "CONNECT #{cs.to_json}#{CR_LF}"
460
530
  end
461
531
 
@@ -567,27 +637,55 @@ module NATS
567
637
  # parser gets what it needs. For the json gem :symbolize_name, for yajl
568
638
  # :symbolize_keys, and for oj :symbol_keys.
569
639
  @server_info = JSON.parse(info, :symbolize_keys => true, :symbolize_names => true, :symbol_keys => true)
570
- if @server_info[:ssl_required] && @ssl
571
- start_tls
640
+
641
+ case
642
+ when (server_using_secure_connection? and client_using_secure_connection?)
643
+ # Allow parameterizing secure connection via EM#start_tls directly if present.
644
+ start_tls(@tls || {})
645
+ when (server_using_secure_connection? and !client_using_secure_connection?)
646
+ # Call unbind since there is a configuration mismatch between client/server
647
+ # anyway and communication cannot happen in this state.
648
+ err_cb.call(NATS::ClientError.new('TLS/SSL required by server'))
649
+ close_connection_after_writing
650
+ when (client_using_secure_connection? and !server_using_secure_connection?)
651
+ err_cb.call(NATS::ClientError.new('TLS/SSL not supported by server'))
652
+ close_connection_after_writing
572
653
  else
573
- if @server_info[:ssl_required]
574
- err_cb.call(NATS::ClientError.new('TLS/SSL required by server'))
575
- elsif @ssl
576
- err_cb.call(NATS::ClientError.new('TLS/SSL not supported by server'))
577
- end
654
+ # Otherwise, use a regular connection.
578
655
  end
656
+
579
657
  if @server_info[:auth_required]
580
658
  current = server_pool.first
581
659
  current[:auth_required] = true
660
+ # Send pending connect followed by ping/pong to ensure we're authorized.
582
661
  queue_server_rt { current[:auth_ok] = true }
583
662
  flush_pending
584
663
  end
664
+
585
665
  @server_info
586
666
  end
587
667
 
588
- def ssl_handshake_completed
589
- @connected = true
590
- flush_pending
668
+ def client_using_secure_connection?
669
+ @tls || @ssl
670
+ end
671
+
672
+ def server_using_secure_connection?
673
+ @server_info[:ssl_required] || @server_info[:tls_required]
674
+ end
675
+
676
+ def ssl_verify_peer(cert)
677
+ ca_file = File.read(@options[:tls][:ca_file])
678
+ ca = OpenSSL::X509::Certificate.new(ca_file)
679
+ incoming = OpenSSL::X509::Certificate.new(cert)
680
+
681
+ unless incoming.issuer.to_s == ca.subject.to_s && incoming.verify(ca.public_key)
682
+ err_cb.call(NATS::ConnectError.new("TLS Verification failed checking issuer based on CA %s" % @options[:ca_file]))
683
+ false
684
+ else
685
+ true
686
+ end
687
+ rescue NATS::ConnectError
688
+ false
591
689
  end
592
690
 
593
691
  def cancel_ping_timer
@@ -598,23 +696,43 @@ module NATS
598
696
  end
599
697
 
600
698
  def connection_completed #:nodoc:
601
- @connected = true unless @ssl
699
+ @parse_state = AWAITING_CONTROL_LINE
700
+
701
+ # Delay sending CONNECT or any other command here until we are sure
702
+ # that we have a valid established secure connection.
703
+ return if (@ssl or @tls)
704
+
705
+ # Mark that we established already TCP connection to the server. In case of TLS,
706
+ # prepare commands which will be dispatched to server and delay flushing until
707
+ # we have processed the INFO line sent by the server and done the handshake.
708
+ @connected = true
709
+ process_connect
710
+ end
711
+
712
+ def ssl_handshake_completed
713
+ @connected = true
714
+ process_connect
715
+ end
602
716
 
717
+ def process_connect #:nodoc:
718
+ # Reset reconnect attempts since TCP connection has been successful at this point.
603
719
  current = server_pool.first
604
720
  current[:was_connected] = true
605
- current[:reconnect_attempts] = 0
721
+ current[:reconnect_attempts] ||= 0
606
722
  cancel_reconnect_timer if reconnecting?
607
723
 
608
- # whip through any pending SUB commands since we replay
724
+ # Whip through any pending SUB commands since we replay
609
725
  # all subscriptions already done anyway.
610
- @pending.delete_if { |sub| sub[0..2] == SUB_OP }
726
+ @pending.delete_if { |sub| sub[0..2] == SUB_OP } if @pending
611
727
  @subs.each_pair { |k, v| send_command("SUB #{v[:subject]} #{v[:queue]} #{k}#{CR_LF}") }
612
728
 
613
729
  unless user_err_cb? or reconnecting?
614
730
  @err_cb = proc { |e| raise e }
615
731
  end
616
732
 
617
- flush_pending unless @ssl
733
+ # We have validated the connection at this point so send CONNECT
734
+ # and any other pending commands which we need to the server.
735
+ flush_pending
618
736
 
619
737
  if (connect_cb and not @conn_cb_called)
620
738
  # We will round trip the server here to make sure all state from any pending commands
@@ -625,17 +743,18 @@ module NATS
625
743
  end
626
744
  end
627
745
 
746
+ # Notify via reconnect callback that we are again plugged again into the system.
628
747
  if reconnecting?
629
748
  @reconnecting = false
630
- @reconnect_cb.call unless @reconnect_cb.nil?
749
+ @reconnect_cb.call(self) unless @reconnect_cb.nil?
631
750
  end
632
751
 
633
- @parse_state = AWAITING_CONTROL_LINE
634
-
635
752
  # Initialize ping timer and processing
636
753
  @pings_outstanding = 0
637
754
  @pongs_received = 0
638
- @ping_timer = EM.add_periodic_timer(@options[:ping_interval]) { send_ping }
755
+ @ping_timer = EM.add_periodic_timer(@options[:ping_interval]) do
756
+ send_ping
757
+ end
639
758
  end
640
759
 
641
760
  def send_ping #:nodoc:
@@ -656,7 +775,7 @@ module NATS
656
775
  end
657
776
 
658
777
  def should_delay_connect?(server)
659
- server[:was_connected] && server[:reconnect_attempts] >= 1
778
+ server[:was_connected] && server[:reconnect_attempts] >= 0
660
779
  end
661
780
 
662
781
  def schedule_reconnect #:nodoc:
@@ -666,9 +785,14 @@ module NATS
666
785
  end
667
786
 
668
787
  def unbind #:nodoc:
788
+ # Allow notifying from which server we were disconnected,
789
+ # but only when we didn't trigger disconnecting ourselves.
790
+ if @disconnect_cb and connected? and not closing?
791
+ disconnect_cb.call(NATS::ConnectError.new(disconnect_error_string))
792
+ end
793
+
669
794
  # If we are closing or shouldn't reconnect, go ahead and disconnect.
670
795
  process_disconnect and return if (closing? or should_not_reconnect?)
671
-
672
796
  @reconnecting = true if connected?
673
797
  @connected = false
674
798
  @pending = @pongs = nil
@@ -698,12 +822,18 @@ module NATS
698
822
  end
699
823
 
700
824
  def disconnect_error_string
701
- return "Client disconnected from server on #{@uri}." if @connected
825
+ return "Client disconnected from server on #{@uri}" if @connected
702
826
  return "Could not connect to server on #{@uri}"
703
827
  end
704
828
 
705
829
  def process_disconnect #:nodoc:
706
- err_cb.call(NATS::ConnectError.new(disconnect_error_string)) if not closing? and @err_cb
830
+ # Mute error callback when user has called NATS.close on purpose.
831
+ if not closing? and @err_cb
832
+ # Always call error callback for compatibility with previous behavior.
833
+ err_cb.call(NATS::ConnectError.new(disconnect_error_string))
834
+ end
835
+ close_cb.call if @close_cb
836
+
707
837
  true # Chaining
708
838
  ensure
709
839
  cancel_ping_timer
@@ -716,13 +846,17 @@ module NATS
716
846
  end
717
847
 
718
848
  def can_reuse_server?(server) #:nodoc:
719
- reconnecting? && server[:was_connected] && server[:reconnect_attempts] <= @options[:max_reconnect_attempts]
849
+ # If we will retry a number of times to reconnect to a server
850
+ # unless we got an error from it already.
851
+ reconnecting? && server[:reconnect_attempts] <= @options[:max_reconnect_attempts] && !server[:error_received]
720
852
  end
721
853
 
722
854
  def attempt_reconnect #:nodoc:
723
855
  @reconnect_timer = nil
724
856
  current = server_pool.first
725
- current[:reconnect_attempts] += 1 if current[:reconnect_attempts]
857
+ current[:reconnect_attempts] ||= 0
858
+ current[:reconnect_attempts] += 1
859
+
726
860
  send_connect_command
727
861
  begin
728
862
  EM.reconnect(@uri.host, @uri.port, self)
@@ -734,11 +868,15 @@ module NATS
734
868
  end
735
869
 
736
870
  def send_command(command, priority = false) #:nodoc:
737
- EM.next_tick { flush_pending } if (connected? && @pending.nil?)
871
+ needs_flush = (connected? && @pending.nil?)
872
+
738
873
  @pending ||= []
739
874
  @pending << command unless priority
740
875
  @pending.unshift(command) if priority
741
876
  @pending_size += command.bytesize
877
+
878
+ EM.next_tick { flush_pending } if needs_flush
879
+
742
880
  flush_pending if (connected? && @pending_size > MAX_PENDING_SIZE)
743
881
  if (@options[:fast_producer_error] && pending_data_size > FAST_PRODUCER_THRESHOLD)
744
882
  err_cb.call(NATS::ClientError.new("Fast Producer: #{pending_data_size} bytes outstanding"))
@@ -773,12 +911,20 @@ module NATS
773
911
  def schedule_primary_and_connect #:nodoc:
774
912
  # Dump the one we were trying if it wasn't connected
775
913
  current = server_pool.shift
776
- # FIXME(dlc) - Should we remove from the list on error?
777
- server_pool << current if (current && (options[:max_reconnect_attempts] < 0 || can_reuse_server?(current) && !current[:error_received]))
778
- # If we are out of options, go ahead and disconnect.
914
+
915
+ # In case there was an error from the server we will take it out from rotation
916
+ # unless we specify infinite reconnects via setting :max_reconnect_attempts to -1
917
+ if current && (options[:max_reconnect_attempts] < 0 || can_reuse_server?(current))
918
+ server_pool << current
919
+ end
920
+
921
+ # If we are out of options, go ahead and disconnect then
922
+ # handle closing connection to NATS.
779
923
  process_disconnect and return if server_pool.empty?
924
+
780
925
  # bind new one
781
926
  next_server = bind_primary
927
+
782
928
  # If the next one was connected and we are trying to reconnect
783
929
  # set up timer if we tried once already.
784
930
  if should_delay_connect?(next_server)
data/lib/nats/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module NATS
2
- VERSION = "0.6.0".freeze
2
+ VERSION = "0.7.0".freeze
3
3
  end
data/nats.gemspec CHANGED
@@ -17,7 +17,7 @@ spec = Gem::Specification.new do |s|
17
17
  s.authors = ['Derek Collison']
18
18
  s.email = ['derek.collison@gmail.com']
19
19
 
20
- s.add_dependency('eventmachine', '~> 1.0', '= 1.0.7')
20
+ s.add_dependency('eventmachine', '~> 1.2', '>= 1.2.0')
21
21
  s.add_dependency('json_pure', '~> 1.8', '>= 1.8.1')
22
22
  s.add_dependency('daemons', '~> 1.1', '>= 1.2.2')
23
23
  s.add_dependency('thin', '~> 1.6', '>= 1.6.3')
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.6.0
4
+ version: 0.7.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: 2016-03-23 00:00:00.000000000 Z
11
+ date: 2016-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eventmachine
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
20
- - - '='
19
+ version: '1.2'
20
+ - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 1.0.7
22
+ version: 1.2.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '1.0'
30
- - - '='
29
+ version: '1.2'
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 1.0.7
32
+ version: 1.2.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: json_pure
35
35
  requirement: !ruby/object:Gem::Requirement