kosmonaut 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,3 +1,7 @@
1
+ 2012-01-20 Krzysztof Kowalik <chris@nu7hat.ch>
2
+
3
+ * lib/kosmonaut/*.rb: optimized sockets thanks to using raw system timeouts
4
+
1
5
  2012-01-20 Krzysztof Kowalik <chris@nu7hat.ch>
2
6
 
3
7
  * test/test_kosmonaut_worker.rb: shortened test time
@@ -1,16 +1,10 @@
1
1
  require 'json'
2
- require 'uri'
3
- require 'socket'
4
- require 'securerandom'
5
- require 'timeout'
6
2
  require 'thread'
7
3
 
8
4
  module Kosmonaut
9
5
  class Client < Socket
10
- include Kosmonaut
11
-
12
6
  # Maximum number of seconds to wait for the request to being processed.
13
- REQUEST_TIMEOUT = 5
7
+ REQUEST_TIMEOUT = 5.0
14
8
 
15
9
  # Public: The Client constructor. Pre-configures the client instance. See
16
10
  # also the Kosmonaut::Socket#initialize for the details.
@@ -73,21 +67,19 @@ module Kosmonaut
73
67
  def perform_request(payload)
74
68
  @mtx.synchronize {
75
69
  response = []
76
- Timeout.timeout(REQUEST_TIMEOUT) {
77
- s = connect
78
- packet = pack(payload)
79
- log("Client/REQ : #{packet.inspect}")
80
- s.write(packet)
81
- response = recv(s)
82
- s.close
83
- }
70
+ s = connect(REQUEST_TIMEOUT)
71
+ packet = pack(payload)
72
+ Kosmonaut.log("Client/REQ : #{packet.inspect}")
73
+ s.write(packet)
74
+ response = recv(s)
75
+ s.close
84
76
  parse_response(response)
85
77
  }
86
78
  end
87
79
 
88
80
  def parse_response(response)
89
81
  cmd = response[0].to_s
90
- log("Client/RES : #{response.join("\n").inspect}")
82
+ Kosmonaut.log("Client/RES : #{response.join("\n").inspect}")
91
83
  case cmd
92
84
  when "OK"
93
85
  return 0
@@ -1,21 +1,38 @@
1
+ require 'uri'
2
+ require 'socket'
3
+ require 'securerandom'
4
+
1
5
  module Kosmonaut
2
6
  class Socket
3
7
  attr_reader :uri
4
8
 
5
9
  def initialize(url)
6
10
  @uri = URI.parse(url)
11
+ @addr = ::Socket.getaddrinfo(@uri.host, nil)
12
+ end
13
+
14
+ def connect(timeout)
15
+ secs = timeout.to_i
16
+ usecs = ((timeout - secs) * 1_000_000).to_i
17
+ optval = [secs, usecs].pack("l_2")
18
+
19
+ s = ::Socket.new(::Socket.const_get(@addr[0][0]), ::Socket::SOCK_STREAM, 0)
20
+ s.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
21
+ s.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_RCVTIMEO, optval)
22
+ s.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_SNDTIMEO, optval)
23
+ s.connect(::Socket.pack_sockaddr_in(@uri.port, @addr[0][3]))
24
+
7
25
  generate_identity
26
+ return s
8
27
  end
9
28
 
10
29
  protected
11
30
 
12
- def connect
13
- TCPSocket.open(@uri.host, @uri.port)
14
- end
15
-
16
- def pack(payload=[])
17
- payload.unshift("")
18
- payload.unshift(@identity)
31
+ def pack(payload=[], with_identity=true)
32
+ if with_identity
33
+ payload.unshift("")
34
+ payload.unshift(@identity)
35
+ end
19
36
  payload.join("\n") + "\n\r\n\r\n"
20
37
  end
21
38
 
@@ -34,7 +51,7 @@ module Kosmonaut
34
51
  end
35
52
  data
36
53
  end
37
-
54
+
38
55
  private
39
56
 
40
57
  def generate_identity
@@ -2,7 +2,7 @@ module Kosmonaut
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 2
5
- PATCH = 3
5
+ PATCH = 4
6
6
 
7
7
  def self.to_s
8
8
  [MAJOR, MINOR, PATCH].join('.')
@@ -3,10 +3,8 @@ require 'thread'
3
3
 
4
4
  module Kosmonaut
5
5
  class Worker < Socket
6
- include Kosmonaut
7
-
8
6
  RECONNECT_DELAY = 1000 # in milliseconds
9
- HEARTBEAT_INTERVAL = 1000 # in milliseconds
7
+ HEARTBEAT_INTERVAL = 500 # in milliseconds
10
8
 
11
9
  def initialize(url)
12
10
  super(url)
@@ -24,20 +22,19 @@ module Kosmonaut
24
22
  while true
25
23
  begin
26
24
  if !alive?
27
- send(@sock, ["QT"]) if @sock
25
+ send(@sock, ["QT"])
28
26
  disconnect
29
27
  break
30
28
  end
31
29
  unless @sock
32
30
  raise Errno::ECONNREFUSED
33
31
  end
34
- msg, cmd = nil, nil
35
- Timeout.timeout(((@heartbeat_ivl * 2).to_f / 1000.0).to_i + 1) {
36
- msg = recv(@sock)
37
- raise Errno::ECONNRESET if @sock.eof? || msg.empty?
38
- log("Worker/RECV : #{msg.join("\n").inspect}")
39
- cmd = msg.shift
40
- }
32
+
33
+ msg = recv(@sock)
34
+ raise Errno::ECONNRESET if @sock.eof? || msg.empty?
35
+ Kosmonaut.log("Worker/RECV : #{msg.join("\n").inspect}")
36
+ cmd = msg.shift
37
+
41
38
  case cmd
42
39
  when "HB"
43
40
  # nothing to do...
@@ -49,11 +46,12 @@ module Kosmonaut
49
46
  when "ER"
50
47
  error_handler(msg.size < 1 ? 597 : msg[0])
51
48
  end
52
- rescue Timeout::Error, Errno::ECONNRESET, Errno::ECONNREFUSED => err
53
- log("Worker/RECONNECT: " + err.to_s)
49
+ rescue Errno::EAGAIN, Errno::ECONNRESET, Errno::ECONNREFUSED, IOError => err
50
+ Kosmonaut.log("Worker/RECONNECT: " + err.to_s)
54
51
  sleep(@reconnect_delay.to_f / 1000.0)
55
52
  reconnect
56
53
  end
54
+ # Send heartbeat if it's time.
57
55
  if Time.now.to_f > @heartbeat_at && @sock
58
56
  send(@sock, ["HB"])
59
57
  @heartbeat_at = Time.now.to_f + (@heartbeat_ivl.to_f / 1000.0)
@@ -75,24 +73,23 @@ module Kosmonaut
75
73
 
76
74
  private
77
75
 
78
- def send(s, payload)
79
- packet = pack(payload.dup)
80
- @sock.write(packet)
81
- log("Worker/SENT : #{(payload.join("\n") + "\n").inspect}")
76
+ def send(s, payload, with_identity=false)
77
+ return unless s
78
+ packet = pack(payload, with_identity)
79
+ s.write(packet)
80
+ Kosmonaut.log("Worker/SENT : #{packet.inspect}")
81
+ rescue Errno::EPIPE
82
82
  end
83
83
 
84
84
  def disconnect
85
- if @sock
86
- @sock.close
87
- @sock = nil
88
- end
85
+ @sock.close if @sock
86
+ rescue IOError
89
87
  end
90
-
88
+
91
89
  def reconnect
92
- disconnect
93
- @sock = connect
94
- send(@sock, ["RD"])
95
- @heartbeat_at = Time.now.to_f + (@heartbeat_ivl.to_f / 1000.0)
90
+ @sock = connect(((@heartbeat_ivl * 2).to_f / 1000.0).to_i + 1)
91
+ send(@sock, ["RD"], true)
92
+ @heartbeat_at = Time.now.to_f + (@heartbeat_ivl.to_f / 1000.0)
96
93
  rescue Errno::ECONNREFUSED
97
94
  end
98
95
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: kosmonaut
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.3
5
+ version: 0.2.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Krzysztof Kowalik
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2012-01-20 00:00:00 Z
14
+ date: 2012-01-22 00:00:00 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: json
@@ -44,12 +44,12 @@ extensions: []
44
44
  extra_rdoc_files: []
45
45
 
46
46
  files:
47
- - lib/kosmonaut/client.rb
48
- - lib/kosmonaut/errors.rb
47
+ - lib/kosmonaut.rb
49
48
  - lib/kosmonaut/socket.rb
50
- - lib/kosmonaut/version.rb
51
49
  - lib/kosmonaut/worker.rb
52
- - lib/kosmonaut.rb
50
+ - lib/kosmonaut/version.rb
51
+ - lib/kosmonaut/errors.rb
52
+ - lib/kosmonaut/client.rb
53
53
  - test/helper.rb
54
54
  - test/test_kosmonaut_client.rb
55
55
  - test/test_kosmonaut_worker.rb
@@ -82,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
82
  requirements: []
83
83
 
84
84
  rubyforge_project:
85
- rubygems_version: 1.8.10
85
+ rubygems_version: 1.8.15
86
86
  signing_key:
87
87
  specification_version: 3
88
88
  summary: Ruby client for the WebRocket backend