nats 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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