nats-pure 0.1.2 → 0.2.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: 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.