nats-pure 0.1.2 → 0.2.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: 5b4990ce0be713e5b1797b7f5e81ce1f5ede4d46
4
- data.tar.gz: cc3b911e3d7af1757ac85aebe25fd7f08c298668
3
+ metadata.gz: a1804a68dcb41e7e76ca9f53fc6b13fc44605090
4
+ data.tar.gz: c2b611901423068cdcd6e6add32b18b9079e47fd
5
5
  SHA512:
6
- metadata.gz: ec94026ad13132ce40c3f85523f2f386ccb38683478e496a9f4ebf2222c80bf8a9c0ac9ad3b53fa0c174ea090f6cbf4f64ba738d0f727d3fb1a378fb7285f814
7
- data.tar.gz: c5a26cd09afc2233d083a23798934fc842c63c84675c07c57c28b3b1786bd7232b367f72abf42d18b5a7ad37ec925b4e713f0154295ec26fdbbca02dbd86903d
6
+ metadata.gz: 7dbaaa96f906080b70992031edbe1d257fe5248f9ff72be6df19050b4554cacce53382946196395d24cae27a3db15de4d4acf07c67097c45d76883423f092419
7
+ data.tar.gz: e4dcd3d62141d47273518fc0252755495162cd0a4d49432647838a06d65203ee4bbbbabe026217567a253ba4da531d293a5e29f6c321e97548419433d1529602
@@ -75,6 +75,9 @@ module NATS
75
75
  # When we do not get a result within a specified time.
76
76
  class Timeout < Error; end
77
77
 
78
+ # When there is an i/o timeout with the socket.
79
+ class SocketTimeoutError < Error; end
80
+
78
81
  # When we use an invalid subject.
79
82
  class BadSubject < Error; end
80
83
 
@@ -162,6 +165,7 @@ module NATS
162
165
  opts[:max_reconnect_attempts] = ENV['NATS_MAX_RECONNECT_ATTEMPTS'].to_i unless ENV['NATS_MAX_RECONNECT_ATTEMPTS'].nil?
163
166
  opts[:ping_interval] = ENV['NATS_PING_INTERVAL'].to_i unless ENV['NATS_PING_INTERVAL'].nil?
164
167
  opts[:max_outstanding_pings] = ENV['NATS_MAX_OUTSTANDING_PINGS'].to_i unless ENV['NATS_MAX_OUTSTANDING_PINGS'].nil?
168
+ opts[:connect_timeout] ||= DEFAULT_CONNECT_TIMEOUT
165
169
  @options = opts
166
170
 
167
171
  # Process servers in the NATS cluster and pick one to connect
@@ -195,7 +199,7 @@ module NATS
195
199
  current[:reconnect_attempts] = 0
196
200
  rescue NoServersError => e
197
201
  @disconnect_cb.call(e) if @disconnect_cb
198
- raise e
202
+ raise @last_err || e
199
203
  rescue => e
200
204
  # Capture sticky error
201
205
  synchronize { @last_err = e }
@@ -207,6 +211,10 @@ module NATS
207
211
  raise e
208
212
  end
209
213
 
214
+ # Clean up any connecting state and close connection without
215
+ # triggering the disconnection/closed callbacks.
216
+ close_connection(DISCONNECTED, false)
217
+
210
218
  # always sleep here to safe guard against errors before current[:was_connected]
211
219
  # is set for the first time
212
220
  sleep @options[:reconnect_time_wait] if @options[:reconnect_time_wait]
@@ -395,7 +403,8 @@ module NATS
395
403
  @last_err = NATS::IO::ServerError.new(err)
396
404
  end
397
405
 
398
- close
406
+ # Process disconnect under a different thread as reading loop
407
+ Thread.new { close }
399
408
  end
400
409
 
401
410
  def process_msg(subject, sid, reply, data)
@@ -451,54 +460,7 @@ module NATS
451
460
  # and there are any pending messages, should not be used while
452
461
  # holding the lock.
453
462
  def close
454
- synchronize do
455
- return if @status == CLOSED
456
- @status = CLOSED
457
- end
458
-
459
- # Kick the flusher so it bails due to closed state
460
- @flush_queue << :fallout
461
- Thread.pass
462
-
463
- # FIXME: More graceful way of handling the following?
464
- # Ensure ping interval and flusher are not running anymore
465
- @ping_interval_thread.exit if @ping_interval_thread.alive?
466
- @flusher_thread.exit if @flusher_thread.alive?
467
- @read_loop_thread.exit if @read_loop_thread.alive?
468
-
469
- # TODO: Delete any other state which we are not using here too.
470
- synchronize do
471
- @pongs.synchronize do
472
- @pongs.each do |pong|
473
- pong.signal
474
- end
475
- @pongs.clear
476
- end
477
-
478
- # Try to write any pending flushes in case
479
- # we have a connection then close it.
480
- begin
481
- cmds = []
482
- cmds << @pending_queue.pop until @pending_queue.empty?
483
-
484
- # FIXME: Fails when empty on TLS connection?
485
- @io.write(cmds.join) unless cmds.empty?
486
- rescue => e
487
- @last_err = e
488
- @err_cb.call(e) if @err_cb
489
- end if @io and not @io.closed?
490
-
491
- # TODO: Destroy any remaining subscriptions
492
- @disconnect_cb.call if @disconnect_cb
493
- @close_cb.call if @close_cb
494
-
495
- # Close the established connection in case
496
- # we still have it.
497
- if @io
498
- @io.close
499
- @io = nil
500
- end
501
- end
463
+ close_connection(CLOSED, true)
502
464
  end
503
465
 
504
466
  def new_inbox
@@ -678,6 +640,8 @@ module NATS
678
640
  return if should_bail
679
641
 
680
642
  synchronize do
643
+ @last_err = e
644
+
681
645
  # If we were connected and configured to reconnect,
682
646
  # then trigger disconnect and start reconnection logic
683
647
  if connected? and should_reconnect?
@@ -710,7 +674,6 @@ module NATS
710
674
 
711
675
  # Otherwise, stop trying to reconnect and close the connection
712
676
  @status = DISCONNECTED
713
- @last_err = e
714
677
  end
715
678
 
716
679
  # Otherwise close the connection to NATS
@@ -799,7 +762,7 @@ module NATS
799
762
  end
800
763
 
801
764
  def process_connect_init
802
- line = @io.read_line
765
+ line = @io.read_line(options[:connect_timeout])
803
766
  _, info_json = line.split(' ')
804
767
  process_info(info_json)
805
768
 
@@ -840,11 +803,11 @@ module NATS
840
803
  # Send ping/pong after connect
841
804
  @io.write(PING_REQUEST)
842
805
 
843
- next_op = @io.read_line
806
+ next_op = @io.read_line(options[:connect_timeout])
844
807
  if @options[:verbose]
845
808
  # Need to get another command here if verbose
846
809
  raise NATS::IO::ConnectError.new("expected to receive +OK") unless next_op =~ NATS::Protocol::OK
847
- next_op = @io.read_line
810
+ next_op = @io.read_line(options[:connect_timeout])
848
811
  end
849
812
 
850
813
  case next_op
@@ -920,6 +883,72 @@ module NATS
920
883
  @reconnect_cb.call if @reconnect_cb
921
884
  end
922
885
 
886
+ def close_connection(conn_status, do_cbs=true)
887
+ synchronize do
888
+ if @status == CLOSED
889
+ @status = conn_status
890
+ return
891
+ end
892
+ end
893
+
894
+ # Kick the flusher so it bails due to closed state
895
+ @flush_queue << :fallout if @flush_queue
896
+ Thread.pass
897
+
898
+ # FIXME: More graceful way of handling the following?
899
+ # Ensure ping interval and flusher are not running anymore
900
+ if @ping_interval_thread and @ping_interval_thread.alive?
901
+ @ping_interval_thread.exit
902
+ end
903
+
904
+ if @flusher_thread and @flusher_thread.alive?
905
+ @flusher_thread.exit
906
+ end
907
+
908
+ if @read_loop_thread and @read_loop_thread.alive?
909
+ @read_loop_thread.exit
910
+ end
911
+
912
+ # TODO: Delete any other state which we are not using here too.
913
+ synchronize do
914
+ @pongs.synchronize do
915
+ @pongs.each do |pong|
916
+ pong.signal
917
+ end
918
+ @pongs.clear
919
+ end
920
+
921
+ # Try to write any pending flushes in case
922
+ # we have a connection then close it.
923
+ should_flush = (@pending_queue && @io && @io.socket && !@io.closed?)
924
+ begin
925
+ cmds = []
926
+ cmds << @pending_queue.pop until @pending_queue.empty?
927
+
928
+ # FIXME: Fails when empty on TLS connection?
929
+ @io.write(cmds.join) unless cmds.empty?
930
+ rescue => e
931
+ @last_err = e
932
+ @err_cb.call(e) if @err_cb
933
+ end if should_flush
934
+
935
+ # TODO: Destroy any remaining subscriptions
936
+ if do_cbs
937
+ @disconnect_cb.call(@last_err) if @disconnect_cb
938
+ @close_cb.call if @close_cb
939
+ end
940
+
941
+ @status = conn_status
942
+
943
+ # Close the established connection in case
944
+ # we still have it.
945
+ if @io
946
+ @io.close if @io.socket
947
+ @io = nil
948
+ end
949
+ end
950
+ end
951
+
923
952
  def start_threads!
924
953
  # Reading loop for gathering data
925
954
  @read_loop_thread = Thread.new { read_loop }
@@ -994,24 +1023,27 @@ module NATS
994
1023
 
995
1024
  def read_line(deadline=nil)
996
1025
  # FIXME: Should accumulate and read in a non blocking way instead
997
- raise Errno::ETIMEDOUT unless ::IO.select([@socket], nil, nil, deadline)
1026
+ unless ::IO.select([@socket], nil, nil, deadline)
1027
+ raise SocketTimeoutError
1028
+ end
998
1029
  @socket.gets
999
1030
  end
1000
1031
 
1001
1032
  def read(max_bytes, deadline=nil)
1033
+
1002
1034
  begin
1003
1035
  return @socket.read_nonblock(max_bytes)
1004
1036
  rescue *NBIO_READ_EXCEPTIONS
1005
1037
  if ::IO.select([@socket], nil, nil, deadline)
1006
1038
  retry
1007
1039
  else
1008
- raise Errno::ETIMEDOUT
1040
+ raise SocketTimeoutError
1009
1041
  end
1010
1042
  rescue *NBIO_WRITE_EXCEPTIONS
1011
1043
  if ::IO.select(nil, [@socket], nil, deadline)
1012
1044
  retry
1013
1045
  else
1014
- raise Errno::ETIMEDOUT
1046
+ raise SocketTimeoutError
1015
1047
  end
1016
1048
  end
1017
1049
  rescue EOFError => e
@@ -1039,13 +1071,13 @@ module NATS
1039
1071
  if ::IO.select(nil, [@socket], nil, deadline)
1040
1072
  retry
1041
1073
  else
1042
- raise Errno::ETIMEDOUT
1074
+ raise SocketTimeoutError
1043
1075
  end
1044
1076
  rescue *NBIO_READ_EXCEPTIONS => e
1045
1077
  if ::IO.select([@socket], nil, nil, deadline)
1046
1078
  retry
1047
1079
  else
1048
- raise Errno::ETIMEDOUT
1080
+ raise SocketTimeoutError
1049
1081
  end
1050
1082
  end
1051
1083
  end
@@ -1070,8 +1102,10 @@ module NATS
1070
1102
 
1071
1103
  begin
1072
1104
  sock.connect_nonblock(sockaddr)
1073
- rescue Errno::EINPROGRESS
1074
- raise Errno::ETIMEDOUT unless ::IO.select(nil, [sock], nil, @connect_timeout)
1105
+ rescue Errno::EINPROGRESS, Errno::EALREADY, ::IO::WaitWritable
1106
+ unless ::IO.select(nil, [sock], nil, @connect_timeout)
1107
+ raise SocketTimeoutError
1108
+ end
1075
1109
 
1076
1110
  # Confirm that connection was established
1077
1111
  begin
@@ -1,7 +1,7 @@
1
1
  module NATS
2
2
  module IO
3
3
  # NOTE: These are all announced to the server on CONNECT
4
- VERSION = "0.1.2"
4
+ VERSION = "0.2.0"
5
5
  LANG = "#{RUBY_ENGINE}2".freeze
6
6
  PROTOCOL = 1
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nats-pure
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Waldemar Quevedo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-13 00:00:00.000000000 Z
11
+ date: 2016-12-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: NATS is an open-source, high-performance, lightweight cloud messaging
14
14
  system.
@@ -41,7 +41,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
41
41
  version: '0'
42
42
  requirements: []
43
43
  rubyforge_project:
44
- rubygems_version: 2.5.2
44
+ rubygems_version: 2.6.8
45
45
  signing_key:
46
46
  specification_version: 4
47
47
  summary: NATS is an open-source, high-performance, lightweight cloud messaging system.