resilient_socket 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4ffdee0e077d518369067ed0b3248ec8c67f2aa2
4
+ data.tar.gz: 82f2d747a1bf0caee65bf4428be6d7e47ea83337
5
+ SHA512:
6
+ metadata.gz: 5c7d639d4af9a6493a34fcf14c06e20d36e95fe352608d01484fc230029d672623364ef79430a508cff5b1d8045250962ac8009fe37b823d24bb8698f75ddad4
7
+ data.tar.gz: 9120d0ee7557ca7f512afe84ed4d3546a2c3c749e5ecd7b1392387db9fbf24ced1363552aa31385f6f1457acdf84d23f32d5399ce6afc90e8de0294cbbc83e42
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'http://rubygems.org'
2
+
3
+ group :test do
4
+ gem "shoulda"
5
+ gem "bson_ext", :platform => 'ruby'
6
+ end
7
+
8
+ gem 'semantic_logger'
9
+
@@ -0,0 +1,38 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.12)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ atomic (1.0.1)
8
+ bourne (1.1.2)
9
+ mocha (= 0.10.5)
10
+ bson (1.8.3)
11
+ bson_ext (1.8.3)
12
+ bson (~> 1.8.3)
13
+ i18n (0.6.4)
14
+ metaclass (0.0.1)
15
+ mocha (0.10.5)
16
+ metaclass (~> 0.0.1)
17
+ multi_json (1.6.1)
18
+ semantic_logger (2.0.0)
19
+ sync_attr
20
+ thread_safe
21
+ shoulda (3.3.2)
22
+ shoulda-context (~> 1.0.1)
23
+ shoulda-matchers (~> 1.4.1)
24
+ shoulda-context (1.0.2)
25
+ shoulda-matchers (1.4.2)
26
+ activesupport (>= 3.0.0)
27
+ bourne (~> 1.1.2)
28
+ sync_attr (0.1.1)
29
+ thread_safe (0.1.0)
30
+ atomic
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ bson_ext
37
+ semantic_logger
38
+ shoulda
data/Rakefile CHANGED
@@ -2,6 +2,7 @@ lib = File.expand_path('../lib/', __FILE__)
2
2
  $:.unshift lib unless $:.include?(lib)
3
3
 
4
4
  require 'rubygems'
5
+ require 'rubygems/package'
5
6
  require 'rake/clean'
6
7
  require 'rake/testtask'
7
8
  require 'date'
@@ -19,11 +20,12 @@ task :gem do |t|
19
20
  spec.date = Date.today.to_s
20
21
  spec.summary = "A Resilient TCP Socket Client with built-in timeouts, retries, and logging"
21
22
  spec.description = "A Resilient TCP Socket Client with built-in timeouts, retries, and logging"
22
- spec.files = FileList["./**/*"].exclude(/.gem$/, /.log$/,/^nbproject/).map{|f| f.sub(/^\.\//, '')}
23
+ spec.files = FileList["./**/*"].exclude(/\.gem$/, /\.log$/,/nbproject/).map{|f| f.sub(/^\.\//, '')}
24
+ spec.license = "Apache License V2.0"
23
25
  spec.has_rdoc = true
24
- spec.add_dependency 'semantic_logger'
26
+ spec.add_dependency 'semantic_logger', '>= 2.1'
25
27
  end
26
- Gem::Builder.new(gemspec).build
28
+ Gem::Package.build gemspec
27
29
  end
28
30
 
29
31
  desc "Run Test Suite"
@@ -29,9 +29,6 @@ module ResilientSocket
29
29
  # * write
30
30
  #
31
31
  # Future:
32
- #
33
- # * Automatic failover to another server should the current server not respond
34
- # to a connection request by supplying an array of host names
35
32
  # * Add auto-reconnect feature to sysread, syswrite, etc...
36
33
  # * To be a drop-in replacement to TCPSocket should also need to implement the
37
34
  # following TCPSocket instance methods: :addr, :peeraddr
@@ -41,6 +38,8 @@ module ResilientSocket
41
38
  # has to be completely destroyed and recreated after a connection failure
42
39
  #
43
40
  class TCPClient
41
+ include SemanticLogger::Loggable
42
+
44
43
  # Supports embedding user supplied data along with this connection
45
44
  # such as sequence number and other connection specific information
46
45
  attr_accessor :user_data
@@ -49,7 +48,7 @@ module ResilientSocket
49
48
  #
50
49
  # Example:
51
50
  # localhost:2000
52
- attr_reader :server, :buffered
51
+ attr_reader :server
53
52
 
54
53
  attr_accessor :read_timeout, :connect_timeout, :connect_retry_count,
55
54
  :retry_count, :connect_retry_interval, :server_selector, :close_on_error
@@ -131,10 +130,10 @@ module ResilientSocket
131
130
  # Default: Half of the :read_timeout ( 30 seconds )
132
131
  #
133
132
  # :log_level [Symbol]
134
- # Only set this level to override the global SemanticLogger logging level
135
- # Can be used to turn on trace or debug level logging in production
133
+ # Set the logging level for the TCPClient
136
134
  # Any valid SemanticLogger log level:
137
135
  # :trace, :debug, :info, :warn, :error, :fatal
136
+ # Default: SemanticLogger.default_level
138
137
  #
139
138
  # :buffered [Boolean]
140
139
  # Whether to use Nagle's Buffering algorithm (http://en.wikipedia.org/wiki/Nagle's_algorithm)
@@ -177,6 +176,15 @@ module ResilientSocket
177
176
  # :random
178
177
  # Randomly select a server from the list every time a connection
179
178
  # is established, including during automatic connection recovery.
179
+ # :nearest
180
+ # FUTURE - Not implemented yet
181
+ # The server with an IP address that most closely matches the
182
+ # local ip address will be attempted first
183
+ # This will result in connections to servers on the localhost
184
+ # first prior to looking at remote servers
185
+ # :ping_time
186
+ # FUTURE - Not implemented yet
187
+ # The server with the lowest ping time will be selected first
180
188
  # Proc:
181
189
  # When a Proc is supplied, it will be called passing in the list
182
190
  # of servers. The Proc must return one server name
@@ -226,8 +234,8 @@ module ResilientSocket
226
234
  raise "Missing mandatory :server or :servers" unless server = params.delete(:server)
227
235
  @servers = [ server ]
228
236
  end
229
- @logger = SemanticLogger::Logger.new("#{self.class.name} #{@servers.inspect}", params.delete(:log_level) || SemanticLogger::Logger.default_level)
230
- params.each_pair {|k,v| @logger.warn "Ignoring unknown option #{k} = #{v}"}
237
+ self.logger = SemanticLogger::Logger.new("#{self.class.name} #{@servers.inspect}", params.delete(:log_level))
238
+ params.each_pair {|k,v| logger.warn "Ignoring unknown option #{k} = #{v}"}
231
239
 
232
240
  # Connect to the Server
233
241
  connect
@@ -318,12 +326,12 @@ module ResilientSocket
318
326
  # For a description of the errors, see Socket#write
319
327
  #
320
328
  def write(data)
321
- @logger.trace("#write ==> sending", data)
322
- @logger.benchmark_debug("#write ==> sent #{data.length} bytes") do
329
+ logger.trace("#write ==> sending", data)
330
+ logger.benchmark_debug("#write ==> sent #{data.length} bytes") do
323
331
  begin
324
332
  @socket.write(data)
325
333
  rescue SystemCallError => exception
326
- @logger.warn "#write Connection failure: #{exception.class}: #{exception.message}"
334
+ logger.warn "#write Connection failure: #{exception.class}: #{exception.message}"
327
335
  close if close_on_error
328
336
  raise ConnectionFailure.new("Send Connection failure: #{exception.class}: #{exception.message}", @server, exception)
329
337
  rescue Exception
@@ -371,13 +379,13 @@ module ResilientSocket
371
379
  #
372
380
  def read(length, buffer=nil, timeout=nil)
373
381
  result = nil
374
- @logger.benchmark_debug("#read <== read #{length} bytes") do
382
+ logger.benchmark_debug("#read <== read #{length} bytes") do
375
383
  if timeout != -1
376
384
  # Block on data to read for @read_timeout seconds
377
385
  ready = begin
378
386
  ready = IO.select([@socket], nil, [@socket], timeout || @read_timeout)
379
387
  rescue IOError => exception
380
- @logger.warn "#read Connection failure while waiting for data: #{exception.class}: #{exception.message}"
388
+ logger.warn "#read Connection failure while waiting for data: #{exception.class}: #{exception.message}"
381
389
  close if close_on_error
382
390
  raise ConnectionFailure.new("#{exception.class}: #{exception.message}", @server, exception)
383
391
  rescue Exception
@@ -388,7 +396,7 @@ module ResilientSocket
388
396
  end
389
397
  unless ready
390
398
  close if close_on_error
391
- @logger.warn "#read Timeout waiting for server to reply"
399
+ logger.warn "#read Timeout waiting for server to reply"
392
400
  raise ReadTimeout.new("Timedout after #{timeout || @read_timeout} seconds trying to read from #{@server}")
393
401
  end
394
402
  end
@@ -396,17 +404,17 @@ module ResilientSocket
396
404
  # Read data from socket
397
405
  begin
398
406
  result = buffer.nil? ? @socket.read(length) : @socket.read(length, buffer)
399
- @logger.trace("#read <== received", result.inspect)
407
+ logger.trace("#read <== received", result.inspect)
400
408
 
401
409
  # EOF before all the data was returned
402
410
  if result.nil? || (result.length < length)
403
411
  close if close_on_error
404
- @logger.warn "#read server closed the connection before #{length} bytes were returned"
412
+ logger.warn "#read server closed the connection before #{length} bytes were returned"
405
413
  raise ConnectionFailure.new("Connection lost while reading data", @server, EOFError.new("end of file reached"))
406
414
  end
407
415
  rescue SystemCallError, IOError => exception
408
416
  close if close_on_error
409
- @logger.warn "#read Connection failure while reading data: #{exception.class}: #{exception.message}"
417
+ logger.warn "#read Connection failure while reading data: #{exception.class}: #{exception.message}"
410
418
  raise ConnectionFailure.new("#{exception.class}: #{exception.message}", @server, exception)
411
419
  rescue Exception
412
420
  # Close the connection on any other exception since the connection
@@ -468,15 +476,15 @@ module ResilientSocket
468
476
  exc_str = exception.cause ? "#{exception.cause.class}: #{exception.cause.message}" : exception.message
469
477
  # Re-raise exceptions that should not be retried
470
478
  if !self.class.reconnect_on_errors.include?(exception.cause.class)
471
- @logger.warn "#retry_on_connection_failure not configured to retry: #{exc_str}"
479
+ logger.warn "#retry_on_connection_failure not configured to retry: #{exc_str}"
472
480
  raise exception
473
481
  elsif retries < @retry_count
474
482
  retries += 1
475
- @logger.warn "#retry_on_connection_failure retry #{retries} due to #{exception.class}: #{exception.message}"
483
+ logger.warn "#retry_on_connection_failure retry #{retries} due to #{exception.class}: #{exception.message}"
476
484
  connect
477
485
  retry
478
486
  end
479
- @logger.error "#retry_on_connection_failure Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
487
+ logger.error "#retry_on_connection_failure Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
480
488
  raise ConnectionFailure.new("After #{retries} retries to host '#{server}': #{exc_str}", @server, exception.cause)
481
489
  end
482
490
  end
@@ -487,7 +495,7 @@ module ResilientSocket
487
495
  def close
488
496
  @socket.close unless @socket.closed?
489
497
  rescue IOError => exception
490
- @logger.warn "IOError when attempting to close socket: #{exception.class}: #{exception.message}"
498
+ logger.warn "IOError when attempting to close socket: #{exception.class}: #{exception.message}"
491
499
  end
492
500
 
493
501
  # Returns whether the socket is closed
@@ -539,7 +547,7 @@ module ResilientSocket
539
547
  # :accept, :accept_nonblock, :bind, :connect, :connect_nonblock, :getpeereid,
540
548
  # :ipv6only!, :listen, :recvfrom_nonblock, :sysaccept
541
549
  retries = 0
542
- @logger.benchmark_info "Connecting to server #{server}" do
550
+ logger.benchmark_info "Connected to #{server}" do
543
551
  host_name, port = server.split(":")
544
552
  port = port.to_i
545
553
 
@@ -570,11 +578,11 @@ module ResilientSocket
570
578
  rescue SystemCallError => exception
571
579
  if retries < @connect_retry_count && self.class.reconnect_on_errors.include?(exception.class)
572
580
  retries += 1
573
- @logger.warn "Connection failure: #{exception.class}: #{exception.message}. Retry: #{retries}"
581
+ logger.warn "Connection failure: #{exception.class}: #{exception.message}. Retry: #{retries}"
574
582
  sleep @connect_retry_interval
575
583
  retry
576
584
  end
577
- @logger.error "Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
585
+ logger.error "Connection failure: #{exception.class}: #{exception.message}. Giving up after #{retries} retries"
578
586
  raise ConnectionFailure.new("After #{retries} connection attempts to host '#{server}': #{exception.class}: #{exception.message}", @server, exception)
579
587
  end
580
588
  end
@@ -1,3 +1,3 @@
1
1
  module ResilientSocket #:nodoc
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -107,8 +107,8 @@ class SimpleTCPServer
107
107
  end
108
108
 
109
109
  if $0 == __FILE__
110
- SemanticLogger::Logger.default_level = :trace
111
- SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new(STDOUT)
110
+ SemanticLogger.default_level = :trace
111
+ SemanticLogger.add_appender(STDOUT)
112
112
  server = SimpleTCPServer.new(2000)
113
113
  server.thread.join
114
114
  end
@@ -8,8 +8,8 @@ require 'shoulda'
8
8
  require 'resilient_socket'
9
9
  require 'simple_tcp_server'
10
10
 
11
- SemanticLogger::Logger.default_level = :trace
12
- SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('test.log')
11
+ SemanticLogger.default_level = :trace
12
+ SemanticLogger.add_appender('test.log')
13
13
 
14
14
  # Unit Test for ResilientSocket::TCPClient
15
15
  class TCPClientTest < Test::Unit::TestCase
metadata CHANGED
@@ -1,32 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resilient_socket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
5
- prerelease:
4
+ version: 0.5.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Reid Morrison
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-11-13 00:00:00.000000000 Z
11
+ date: 2013-04-03 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: semantic_logger
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
- version: '0'
19
+ version: '2.1'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
- version: '0'
26
+ version: '2.1'
30
27
  description: A Resilient TCP Socket Client with built-in timeouts, retries, and logging
31
28
  email:
32
29
  - reidmo@gmail.com
@@ -34,44 +31,39 @@ executables: []
34
31
  extensions: []
35
32
  extra_rdoc_files: []
36
33
  files:
34
+ - Gemfile
35
+ - Gemfile.lock
36
+ - LICENSE.txt
37
+ - README.md
38
+ - Rakefile
39
+ - lib/resilient_socket.rb
37
40
  - lib/resilient_socket/exceptions.rb
38
41
  - lib/resilient_socket/tcp_client.rb
39
42
  - lib/resilient_socket/version.rb
40
- - lib/resilient_socket.rb
41
- - LICENSE.txt
42
- - nbproject/private/config.properties
43
- - nbproject/private/private.properties
44
- - nbproject/private/private.xml
45
- - nbproject/private/rake-d.txt
46
- - nbproject/project.properties
47
- - nbproject/project.xml
48
- - Rakefile
49
- - README.md
50
43
  - test/simple_tcp_server.rb
51
44
  - test/tcp_client_test.rb
52
- - test.log.working
53
45
  homepage: https://github.com/ClarityServices/resilient_socket
54
- licenses: []
46
+ licenses:
47
+ - Apache License V2.0
48
+ metadata: {}
55
49
  post_install_message:
56
50
  rdoc_options: []
57
51
  require_paths:
58
52
  - lib
59
53
  required_ruby_version: !ruby/object:Gem::Requirement
60
- none: false
61
54
  requirements:
62
- - - ! '>='
55
+ - - '>='
63
56
  - !ruby/object:Gem::Version
64
57
  version: '0'
65
58
  required_rubygems_version: !ruby/object:Gem::Requirement
66
- none: false
67
59
  requirements:
68
- - - ! '>='
60
+ - - '>='
69
61
  - !ruby/object:Gem::Version
70
62
  version: '0'
71
63
  requirements: []
72
64
  rubyforge_project:
73
- rubygems_version: 1.8.24
65
+ rubygems_version: 2.0.2
74
66
  signing_key:
75
- specification_version: 3
67
+ specification_version: 4
76
68
  summary: A Resilient TCP Socket Client with built-in timeouts, retries, and logging
77
69
  test_files: []
File without changes
@@ -1,3 +0,0 @@
1
- file.reference.resilient_socket-lib=/Users/rmorrison/Sandbox/resilient_socket/lib
2
- file.reference.resilient_socket-test=/Users/rmorrison/Sandbox/resilient_socket/test
3
- platform.active=Ruby_0
@@ -1,4 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project-private xmlns="http://www.netbeans.org/ns/project-private/1">
3
- <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
4
- </project-private>
@@ -1,4 +0,0 @@
1
- clean=
2
- clobber=
3
- gem=
4
- test=
@@ -1,7 +0,0 @@
1
- file.reference.resilient_socket-lib=lib
2
- file.reference.resilient_socket-test=test
3
- main.file=
4
- platform.active=Ruby
5
- source.encoding=UTF-8
6
- src.dir=${file.reference.resilient_socket-lib}
7
- test.src.dir=${file.reference.resilient_socket-test}
@@ -1,15 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project xmlns="http://www.netbeans.org/ns/project/1">
3
- <type>org.netbeans.modules.ruby.rubyproject</type>
4
- <configuration>
5
- <data xmlns="http://www.netbeans.org/ns/ruby-project/1">
6
- <name>resilient_socket</name>
7
- <source-roots>
8
- <root id="src.dir"/>
9
- </source-roots>
10
- <test-roots>
11
- <root id="test.src.dir"/>
12
- </test-roots>
13
- </data>
14
- </configuration>
15
- </project>
Binary file