cod 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.txt +11 -0
- data/README +1 -1
- data/examples/example_scaffold.rb +2 -0
- data/examples/protocol-buffers/README +2 -1
- data/examples/tcp_get_ext.rb +38 -0
- data/lib/cod/service.rb +3 -1
- data/lib/cod/tcp_client.rb +14 -6
- data/lib/cod/tcp_server.rb +66 -26
- metadata +17 -23
- data/Gemfile +0 -3
- data/examples/presence/client.rb +0 -15
- data/examples/presence/server.rb +0 -30
- data/examples/queue/README +0 -9
- data/examples/queue/client.rb +0 -31
- data/examples/queue/queue.rb +0 -51
- data/examples/queue/send.rb +0 -9
data/HISTORY.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
= 0.4.4 / 7Mar2012
|
2
|
+
|
3
|
+
+ Uses IO.select in the server as well, not polling for accept. This should
|
4
|
+
further reduce the CPU time consumed by servers.
|
5
|
+
|
6
|
+
! Fixes a bug where server would hang forever with messages to return in
|
7
|
+
its queue.
|
8
|
+
|
9
|
+
+ Switching to YARD for documentation, please be patient while the whole
|
10
|
+
gets a workover. This should be finished by 0.4.6 at the latest.
|
11
|
+
|
1
12
|
= 0.4.3 / 28Feb2012
|
2
13
|
|
3
14
|
! Fixes a few bugs when using tcp channels (connection was not made or not
|
data/README
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
3
|
+
require 'cod'
|
4
|
+
require 'example_scaffold'
|
5
|
+
|
6
|
+
2.times do
|
7
|
+
client {
|
8
|
+
chan = Cod.tcp('localhost:1234')
|
9
|
+
chan.put :get_client_id
|
10
|
+
p [:client_id, chan.get]
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
server {
|
15
|
+
server = Cod.tcp_server('localhost:1234')
|
16
|
+
client_id = 0
|
17
|
+
|
18
|
+
loop do
|
19
|
+
msg, chan = server.get_ext
|
20
|
+
|
21
|
+
p [:incoming, msg, chan.object_id.to_s(16)]
|
22
|
+
begin
|
23
|
+
case msg
|
24
|
+
when :get_client_id
|
25
|
+
client_id += 1
|
26
|
+
chan.put client_id
|
27
|
+
end
|
28
|
+
|
29
|
+
ensure
|
30
|
+
# Closes connections after one request.
|
31
|
+
chan.close
|
32
|
+
end
|
33
|
+
|
34
|
+
break if client_id >= 2
|
35
|
+
end
|
36
|
+
}
|
37
|
+
|
38
|
+
run
|
data/lib/cod/service.rb
CHANGED
@@ -4,7 +4,7 @@ module Cod
|
|
4
4
|
# answer. It solves problems related to timeouts, getting _your_ answer and
|
5
5
|
# not any kind of answer, etc...
|
6
6
|
#
|
7
|
-
# Synopsis
|
7
|
+
# == Synopsis
|
8
8
|
# # On the server end:
|
9
9
|
# service = server_channel.service
|
10
10
|
# service.one { |request| :answer }
|
@@ -40,6 +40,8 @@ module Cod
|
|
40
40
|
# Use Cod::Client to perform the service call. This will keep track of
|
41
41
|
# messages sent and answers received and a couple of other things.
|
42
42
|
#
|
43
|
+
# @yield [Object] request made by the client. The return value of the
|
44
|
+
# block will be returned to the client.
|
43
45
|
#
|
44
46
|
def one
|
45
47
|
rq, answer_chan = @channel.get
|
data/lib/cod/tcp_client.rb
CHANGED
@@ -25,12 +25,15 @@ module Cod
|
|
25
25
|
@serializer = serializer
|
26
26
|
@destination = destination
|
27
27
|
|
28
|
+
# TODO remove this soon
|
29
|
+
fail "Deprecated API" if destination.kind_of?(TCPSocket)
|
30
|
+
|
28
31
|
# TcpClient handles two cases: Construction via an url (destination is a
|
29
32
|
# string) and construction via a connection that has been
|
30
33
|
# preestablished (destination is a socket):
|
31
|
-
if destination.respond_to?(:
|
32
|
-
#
|
33
|
-
@connection =
|
34
|
+
if destination.respond_to?(:established?)
|
35
|
+
# Should be a connection already.
|
36
|
+
@connection = destination
|
34
37
|
else
|
35
38
|
@connection = RobustConnection.new(destination)
|
36
39
|
end
|
@@ -115,6 +118,8 @@ module Cod
|
|
115
118
|
# the other end (the deserializing end). What the deserializing code does
|
116
119
|
# with this is his problem.
|
117
120
|
#
|
121
|
+
# @private
|
122
|
+
#
|
118
123
|
OtherEnd = Struct.new(:destination) # :nodoc:
|
119
124
|
|
120
125
|
def _dump(level) # :nodoc:
|
@@ -235,9 +240,12 @@ module Cod
|
|
235
240
|
# the TcpServers clients: the tcp server manages the back channels, so
|
236
241
|
# the created channel is lent its socket only.
|
237
242
|
#
|
243
|
+
# @private
|
244
|
+
#
|
238
245
|
class Connection # :nodoc:
|
239
|
-
def initialize(socket)
|
240
|
-
@
|
246
|
+
def initialize(socket, owner)
|
247
|
+
@owner = owner
|
248
|
+
@socket = socket
|
241
249
|
end
|
242
250
|
attr_reader :socket
|
243
251
|
def try_connect
|
@@ -252,7 +260,7 @@ module Cod
|
|
252
260
|
@socket.write(buffer)
|
253
261
|
end
|
254
262
|
def close
|
255
|
-
@socket
|
263
|
+
@owner.request_close(socket)
|
256
264
|
end
|
257
265
|
end
|
258
266
|
end
|
data/lib/cod/tcp_server.rb
CHANGED
@@ -4,7 +4,7 @@ module Cod
|
|
4
4
|
# A tcp server channel. Messages are read from any of the connected sockets
|
5
5
|
# in a round robin fashion.
|
6
6
|
#
|
7
|
-
# Synopsis
|
7
|
+
# == Synopsis
|
8
8
|
# server = Cod.tcp_server('localhost:12345')
|
9
9
|
# server.get # 'a message'
|
10
10
|
# msg, chan = server.get_ext
|
@@ -13,13 +13,11 @@ module Cod
|
|
13
13
|
# connected sockets, this is up to you to implement. Instead, you can use
|
14
14
|
# one of two ways to obtain a channel for talking back to a specific client:
|
15
15
|
#
|
16
|
-
# Using #get_ext:
|
17
16
|
# msg, chan = server.get_ext
|
18
|
-
#
|
17
|
+
#
|
19
18
|
# chan is a two way connected channel to the specific client that has opened
|
20
19
|
# its communication with msg.
|
21
20
|
#
|
22
|
-
# Using plain #get:
|
23
21
|
# # on the client:
|
24
22
|
# client.put [client, :msg]
|
25
23
|
# # on the server
|
@@ -37,10 +35,14 @@ module Cod
|
|
37
35
|
@serializer = serializer
|
38
36
|
end
|
39
37
|
|
40
|
-
# Receives one object from the channel.
|
38
|
+
# Receives one object from the channel. This will receive one message from
|
39
|
+
# one of the connected clients in a round-robin fashion.
|
41
40
|
#
|
42
|
-
#
|
41
|
+
# @example
|
43
42
|
# channel.get # => object
|
43
|
+
#
|
44
|
+
# @param opts [Hash]
|
45
|
+
# @return [Object] message sent by one of the clients
|
44
46
|
#
|
45
47
|
def get(opts={})
|
46
48
|
msg, socket = _get(opts)
|
@@ -54,14 +56,18 @@ module Cod
|
|
54
56
|
# Using this method, the server can communicate back to its clients
|
55
57
|
# individually instead of collectively.
|
56
58
|
#
|
57
|
-
#
|
59
|
+
# @example Answering to the client that sent a specific message
|
58
60
|
# msg, chan = server.get_ext
|
59
61
|
# chan.put :answer
|
62
|
+
#
|
63
|
+
# @param opts [Hash]
|
64
|
+
# @return [Array<Object, TcpClient>] tuple of the message that was sent
|
65
|
+
# a channel back to the client that sent the message
|
60
66
|
def get_ext(opts={})
|
61
67
|
msg, socket = _get(opts)
|
62
68
|
return [
|
63
69
|
msg,
|
64
|
-
|
70
|
+
produce_back_channel(socket)]
|
65
71
|
end
|
66
72
|
|
67
73
|
# Closes the channel.
|
@@ -89,37 +95,65 @@ module Cod
|
|
89
95
|
def service
|
90
96
|
Service.new(self)
|
91
97
|
end
|
92
|
-
|
98
|
+
|
99
|
+
# @note It is really more convenient to just construct a Cod.tcp_client
|
93
100
|
# and ask that for a client object. In the case of TCP, this is enough.
|
94
101
|
#
|
95
102
|
def client(answers_to)
|
96
103
|
Service::Client.new(answers_to, answers_to)
|
97
104
|
end
|
98
105
|
|
106
|
+
# ------------------------------------------------------- connection owner
|
107
|
+
|
108
|
+
# Notifies the TcpServer that one of its connections needs to be closed.
|
109
|
+
# This can be triggered by using #get_ext to obtain a handle to connections
|
110
|
+
# and then calling #close on that connection.
|
111
|
+
#
|
112
|
+
# @param socket [TCPSocket] the socket that needs to be closed
|
113
|
+
# @return [void]
|
114
|
+
#
|
115
|
+
def request_close(socket)
|
116
|
+
@client_sockets.delete(socket)
|
117
|
+
socket.close
|
118
|
+
end
|
119
|
+
|
99
120
|
private
|
100
121
|
def _get(opts)
|
101
122
|
loop do
|
102
|
-
#
|
103
|
-
|
123
|
+
# Return a buffered message if there is one left.
|
124
|
+
return @messages.shift unless @messages.empty?
|
104
125
|
|
105
|
-
#
|
106
|
-
# same client.
|
126
|
+
# Shuffle the socket list around, so we don't always read from the
|
127
|
+
# same client first.
|
107
128
|
socket_list = round_robin(@client_sockets)
|
108
|
-
|
109
|
-
#
|
110
|
-
|
129
|
+
|
130
|
+
# Append the server socket to be able to react to new connections
|
131
|
+
# that are made.
|
132
|
+
socket_list << @socket
|
133
|
+
|
134
|
+
# Sleep until either a new connection is made or data is available on
|
135
|
+
# one of the old connections.
|
136
|
+
rr, _, _ = IO.select(socket_list, nil, nil)
|
111
137
|
next unless rr
|
112
138
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
else
|
118
|
-
consume_pending io, opts
|
119
|
-
end
|
139
|
+
# Accept new connections
|
140
|
+
if rr.include?(@socket)
|
141
|
+
accept_new_connections
|
142
|
+
rr.delete(@socket)
|
120
143
|
end
|
121
144
|
|
122
|
-
|
145
|
+
handle_socket_events(rr, opts)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def handle_socket_events(sockets, opts)
|
150
|
+
sockets.each do |io|
|
151
|
+
if io.eof?
|
152
|
+
@client_sockets.delete(io)
|
153
|
+
io.close
|
154
|
+
else
|
155
|
+
consume_pending io, opts
|
156
|
+
end
|
123
157
|
end
|
124
158
|
end
|
125
159
|
|
@@ -130,14 +164,14 @@ module Cod
|
|
130
164
|
io]
|
131
165
|
|
132
166
|
# More messages from this socket?
|
133
|
-
return unless IO.select([io], nil, nil, 0.
|
167
|
+
return unless IO.select([io], nil, nil, 0.0001)
|
134
168
|
end
|
135
169
|
end
|
136
170
|
|
137
171
|
def deserialize(io)
|
138
172
|
@serializer.de(io) { |obj|
|
139
173
|
obj.kind_of?(TcpClient::OtherEnd) ?
|
140
|
-
|
174
|
+
produce_back_channel(io) :
|
141
175
|
obj
|
142
176
|
}
|
143
177
|
end
|
@@ -161,5 +195,11 @@ module Cod
|
|
161
195
|
rescue Errno::EAGAIN
|
162
196
|
# This means that there are no sockets to accept. Continue.
|
163
197
|
end
|
198
|
+
|
199
|
+
def produce_back_channel(socket)
|
200
|
+
TcpClient.new(
|
201
|
+
TcpClient::Connection.new(socket, self),
|
202
|
+
@serializer)
|
203
|
+
end
|
164
204
|
end
|
165
205
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &70125556634640 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70125556634640
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70125556634180 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70125556634180
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: flexmock
|
38
|
-
requirement: &
|
38
|
+
requirement: &70125556633740 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70125556633740
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: yard
|
49
|
-
requirement: &
|
49
|
+
requirement: &70125556633260 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70125556633260
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: guard
|
60
|
-
requirement: &
|
60
|
+
requirement: &70125556632740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70125556632740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: growl
|
71
|
-
requirement: &
|
71
|
+
requirement: &70125556632280 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70125556632280
|
80
80
|
description:
|
81
81
|
email: kaspar.schiess@absurd.li
|
82
82
|
executables: []
|
@@ -84,7 +84,6 @@ extensions: []
|
|
84
84
|
extra_rdoc_files:
|
85
85
|
- README
|
86
86
|
files:
|
87
|
-
- Gemfile
|
88
87
|
- HISTORY.txt
|
89
88
|
- LICENSE
|
90
89
|
- Rakefile
|
@@ -114,16 +113,11 @@ files:
|
|
114
113
|
- examples/master_child.rb
|
115
114
|
- examples/netcat/README
|
116
115
|
- examples/netcat/server.rb
|
117
|
-
- examples/presence/client.rb
|
118
|
-
- examples/presence/server.rb
|
119
116
|
- examples/protocol-buffers/master_child.rb
|
120
117
|
- examples/protocol-buffers/README
|
121
|
-
- examples/queue/client.rb
|
122
|
-
- examples/queue/queue.rb
|
123
|
-
- examples/queue/README
|
124
|
-
- examples/queue/send.rb
|
125
118
|
- examples/service.rb
|
126
119
|
- examples/tcp.rb
|
120
|
+
- examples/tcp_get_ext.rb
|
127
121
|
homepage: http://kschiess.github.com/cod
|
128
122
|
licenses: []
|
129
123
|
post_install_message:
|
@@ -140,7 +134,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
134
|
version: '0'
|
141
135
|
segments:
|
142
136
|
- 0
|
143
|
-
hash: -
|
137
|
+
hash: -763744089584274604
|
144
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
139
|
none: false
|
146
140
|
requirements:
|
@@ -149,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
143
|
version: '0'
|
150
144
|
segments:
|
151
145
|
- 0
|
152
|
-
hash: -
|
146
|
+
hash: -763744089584274604
|
153
147
|
requirements: []
|
154
148
|
rubyforge_project:
|
155
149
|
rubygems_version: 1.8.16
|
data/Gemfile
DELETED
data/examples/presence/client.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
|
5
|
-
raise unless ARGV.first
|
6
|
-
|
7
|
-
client = Cod.tcp('localhost:12345')
|
8
|
-
client.put [client, ARGV.first]
|
9
|
-
|
10
|
-
puts "Waiting..."
|
11
|
-
$stdin.gets
|
12
|
-
client.close
|
13
|
-
$stdin.gets
|
14
|
-
|
15
|
-
|
data/examples/presence/server.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
|
2
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
3
|
-
require 'cod'
|
4
|
-
|
5
|
-
|
6
|
-
present = {}
|
7
|
-
server = Cod.tcpserver('localhost:12345')
|
8
|
-
|
9
|
-
loop do
|
10
|
-
# Process connection requests
|
11
|
-
while server.waiting?
|
12
|
-
connection, attributes = server.get
|
13
|
-
|
14
|
-
present[connection] = attributes
|
15
|
-
end
|
16
|
-
|
17
|
-
# Check if all connections are alive
|
18
|
-
remove = []
|
19
|
-
present.each do |conn, attrs|
|
20
|
-
if conn.connected?
|
21
|
-
puts "Alive: #{attrs.inspect}"
|
22
|
-
else
|
23
|
-
puts "Dead: #{attrs.inspect}"
|
24
|
-
remove << conn
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
remove.each { |conn| present.delete(conn) }
|
29
|
-
sleep 1
|
30
|
-
end
|
data/examples/queue/README
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
A small queue like example.
|
2
|
-
|
3
|
-
run ruby send.rb N to send N messages through queue.rb to client.rb.
|
4
|
-
Client will print statistics (calls per second) every 100 messages.
|
5
|
-
|
6
|
-
Problems:
|
7
|
-
- queue.rb seems to always consume 100% CPU
|
8
|
-
- number of messages per second is way low
|
9
|
-
- some exceptions are still not handled correctly
|
data/examples/queue/client.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
queue = Cod.tcp('localhost:12345')
|
5
|
-
|
6
|
-
queue.put [:join, queue]
|
7
|
-
|
8
|
-
class CallCounter
|
9
|
-
attr_reader :n
|
10
|
-
def initialize
|
11
|
-
@n = 0
|
12
|
-
@last_lap = [0, Time.now]
|
13
|
-
end
|
14
|
-
def inc
|
15
|
-
@n += 1
|
16
|
-
end
|
17
|
-
def calls_per_sec
|
18
|
-
ln, ll = @last_lap
|
19
|
-
@last_lap = [@n, Time.now]
|
20
|
-
|
21
|
-
(@n - ln) / (Time.now - ll)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
cc = CallCounter.new
|
26
|
-
loop do
|
27
|
-
wi = queue.get
|
28
|
-
|
29
|
-
cc.inc
|
30
|
-
puts cc.calls_per_sec if cc.n%100==0
|
31
|
-
end
|
data/examples/queue/queue.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
class Queue
|
5
|
-
def initialize(url)
|
6
|
-
@url = url
|
7
|
-
connect
|
8
|
-
end
|
9
|
-
|
10
|
-
def connect
|
11
|
-
@clients = []
|
12
|
-
@server = Cod.tcpserver(@url)
|
13
|
-
end
|
14
|
-
|
15
|
-
def run
|
16
|
-
loop do
|
17
|
-
handle_commands
|
18
|
-
|
19
|
-
check_connections
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def handle_commands
|
24
|
-
while @server.waiting?
|
25
|
-
cmd, *rest = @server.get
|
26
|
-
|
27
|
-
dispatch_command cmd, rest
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def dispatch_command(cmd, rest)
|
32
|
-
self.send("cmd_#{cmd}", *rest)
|
33
|
-
end
|
34
|
-
|
35
|
-
def cmd_join(connection)
|
36
|
-
puts "Join at #{Time.now}."
|
37
|
-
@clients << connection
|
38
|
-
end
|
39
|
-
|
40
|
-
def cmd_work_item
|
41
|
-
@clients.each do |client|
|
42
|
-
client.put :work_item
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def check_connections
|
47
|
-
@clients.keep_if { |client| client.connected? }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
Queue.new('localhost:12345').run
|