tmm1-amqp 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +6 -1
- data/Rakefile +15 -0
- data/amqp.gemspec +83 -0
- data/amqp.todo +32 -0
- data/doc/EXAMPLE_01_PINGPONG +2 -0
- data/doc/EXAMPLE_02_CLOCK +2 -0
- data/doc/EXAMPLE_03_STOCKS +2 -0
- data/doc/EXAMPLE_04_MULTICLOCK +2 -0
- data/doc/EXAMPLE_05_ACK +2 -0
- data/doc/EXAMPLE_05_POP +2 -0
- data/doc/EXAMPLE_06_HASHTABLE +2 -0
- data/examples/mq/{simple-ack.rb → ack.rb} +2 -3
- data/examples/mq/clock.rb +2 -2
- data/examples/mq/hashtable.rb +3 -3
- data/examples/mq/{simple.rb → internal.rb} +0 -0
- data/examples/mq/logger.rb +3 -3
- data/examples/mq/multiclock.rb +49 -0
- data/examples/mq/pingpong.rb +2 -2
- data/examples/mq/{simple-get.rb → pop.rb} +0 -0
- data/examples/mq/primes.rb +3 -3
- data/examples/mq/stocks.rb +2 -2
- data/lib/amqp.rb +10 -0
- data/lib/amqp/client.rb +4 -4
- data/lib/amqp/server.rb +99 -0
- data/lib/mq.rb +86 -3
- data/lib/mq/queue.rb +10 -4
- data/lib/mq/rpc.rb +3 -1
- data/old/README +30 -0
- data/old/Rakefile +12 -0
- data/old/amqp-0.8.json +606 -0
- data/old/amqp_spec.rb +796 -0
- data/old/amqpc.rb +695 -0
- data/old/codegen.rb +148 -0
- data/research/api.rb +88 -0
- data/research/primes-forked.rb +63 -0
- data/research/primes-processes.rb +135 -0
- data/research/primes-threaded.rb +49 -0
- metadata +40 -10
data/README
CHANGED
@@ -21,10 +21,14 @@ To use with RabbitMQ, first run the server:
|
|
21
21
|
|
22
22
|
To get started, refer to the various bundled examples:
|
23
23
|
|
24
|
-
ruby examples/mq/simple.rb # low-level Queue/Exchange api
|
25
24
|
ruby examples/mq/pingpong.rb # 1-1 communication using amq.direct
|
26
25
|
ruby examples/mq/clock.rb # 1-N communication using amq.fanout
|
27
26
|
ruby examples/mq/stocks.rb # 1-subscriber communication using amq.topic
|
27
|
+
|
28
|
+
ruby examples/mq/multiclock.rb # header based routing (new rabbitmq feature)
|
29
|
+
ruby examples/mq/ack.rb # using ack
|
30
|
+
ruby examples/mq/pop.rb # pop off messages one at a time
|
31
|
+
|
28
32
|
ruby examples/mq/hashtable.rb # simple async rpc layer
|
29
33
|
ruby examples/mq/primes.rb 4 # parallelized prime number generation
|
30
34
|
ruby examples/mq/logger.rb # simple logging api
|
@@ -32,6 +36,7 @@ To get started, refer to the various bundled examples:
|
|
32
36
|
For more details into the lower level AMQP client API, run the simple client example:
|
33
37
|
|
34
38
|
ruby examples/amqp/simple.rb # low-level AMQP api
|
39
|
+
ruby examples/mq/internal.rb # low-level Queue/Exchange api
|
35
40
|
|
36
41
|
Or refer to protocol/doc.txt, which enumerates packets sent between a server and client
|
37
42
|
during a typical session, in both binary and decoded formats.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
task :codegen do
|
2
|
+
sh 'ruby protocol/codegen.rb > lib/amqp/spec.rb'
|
3
|
+
sh 'ruby lib/amqp/spec.rb'
|
4
|
+
end
|
5
|
+
|
6
|
+
task :spec do
|
7
|
+
sh 'bacon lib/amqp.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
task :gem do
|
11
|
+
sh 'gem build *.gemspec'
|
12
|
+
end
|
13
|
+
|
14
|
+
task :pkg => :gem
|
15
|
+
task :package => :gem
|
data/amqp.gemspec
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
spec = Gem::Specification.new do |s|
|
2
|
+
s.name = 'amqp'
|
3
|
+
s.version = '0.6.1'
|
4
|
+
s.date = '2009-01-09'
|
5
|
+
s.summary = 'AMQP client implementation in Ruby/EventMachine'
|
6
|
+
s.email = "amqp@tmm1.net"
|
7
|
+
s.homepage = "http://amqp.rubyforge.org/"
|
8
|
+
s.description = "AMQP client implementation in Ruby/EventMachine"
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.rdoc_options = '--include=examples'
|
11
|
+
|
12
|
+
# ruby -rpp -e' pp `git ls-files`.split("\n").grep(/^(doc|README)/) '
|
13
|
+
s.extra_rdoc_files = [
|
14
|
+
"README",
|
15
|
+
"doc/EXAMPLE_01_PINGPONG",
|
16
|
+
"doc/EXAMPLE_02_CLOCK",
|
17
|
+
"doc/EXAMPLE_03_STOCKS",
|
18
|
+
"doc/EXAMPLE_04_MULTICLOCK",
|
19
|
+
"doc/EXAMPLE_05_ACK",
|
20
|
+
"doc/EXAMPLE_05_POP",
|
21
|
+
"doc/EXAMPLE_06_HASHTABLE"
|
22
|
+
]
|
23
|
+
|
24
|
+
s.authors = ["Aman Gupta"]
|
25
|
+
s.add_dependency('eventmachine', '>= 0.12.4')
|
26
|
+
|
27
|
+
# ruby -rpp -e' pp `git ls-files`.split("\n") '
|
28
|
+
s.files = [
|
29
|
+
"README",
|
30
|
+
"Rakefile",
|
31
|
+
"amqp.gemspec",
|
32
|
+
"amqp.todo",
|
33
|
+
"doc/EXAMPLE_01_PINGPONG",
|
34
|
+
"doc/EXAMPLE_02_CLOCK",
|
35
|
+
"doc/EXAMPLE_03_STOCKS",
|
36
|
+
"doc/EXAMPLE_04_MULTICLOCK",
|
37
|
+
"doc/EXAMPLE_05_ACK",
|
38
|
+
"doc/EXAMPLE_05_POP",
|
39
|
+
"doc/EXAMPLE_06_HASHTABLE",
|
40
|
+
"examples/amqp/simple.rb",
|
41
|
+
"examples/mq/ack.rb",
|
42
|
+
"examples/mq/clock.rb",
|
43
|
+
"examples/mq/pop.rb",
|
44
|
+
"examples/mq/hashtable.rb",
|
45
|
+
"examples/mq/internal.rb",
|
46
|
+
"examples/mq/logger.rb",
|
47
|
+
"examples/mq/multiclock.rb",
|
48
|
+
"examples/mq/pingpong.rb",
|
49
|
+
"examples/mq/primes-simple.rb",
|
50
|
+
"examples/mq/primes.rb",
|
51
|
+
"examples/mq/stocks.rb",
|
52
|
+
"lib/amqp.rb",
|
53
|
+
"lib/amqp/buffer.rb",
|
54
|
+
"lib/amqp/client.rb",
|
55
|
+
"lib/amqp/frame.rb",
|
56
|
+
"lib/amqp/protocol.rb",
|
57
|
+
"lib/amqp/server.rb",
|
58
|
+
"lib/amqp/spec.rb",
|
59
|
+
"lib/ext/blankslate.rb",
|
60
|
+
"lib/ext/em.rb",
|
61
|
+
"lib/ext/emfork.rb",
|
62
|
+
"lib/mq.rb",
|
63
|
+
"lib/mq/exchange.rb",
|
64
|
+
"lib/mq/header.rb",
|
65
|
+
"lib/mq/logger.rb",
|
66
|
+
"lib/mq/queue.rb",
|
67
|
+
"lib/mq/rpc.rb",
|
68
|
+
"old/README",
|
69
|
+
"old/Rakefile",
|
70
|
+
"old/amqp-0.8.json",
|
71
|
+
"old/amqp_spec.rb",
|
72
|
+
"old/amqpc.rb",
|
73
|
+
"old/codegen.rb",
|
74
|
+
"protocol/amqp-0.8.json",
|
75
|
+
"protocol/amqp-0.8.xml",
|
76
|
+
"protocol/codegen.rb",
|
77
|
+
"protocol/doc.txt",
|
78
|
+
"research/api.rb",
|
79
|
+
"research/primes-forked.rb",
|
80
|
+
"research/primes-processes.rb",
|
81
|
+
"research/primes-threaded.rb"
|
82
|
+
]
|
83
|
+
end
|
data/amqp.todo
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
- breaks with header values that are nil
|
2
|
+
- breaks with header values that are ruby objects (convert to strings?)
|
3
|
+
- sending utf8 data in 1.9 breaks
|
4
|
+
|
5
|
+
- generate amqp/spec.rb from original xml spec
|
6
|
+
- add peek and pop to queues
|
7
|
+
- use rabbitmq generated consumer tag from basic.consume-ok reply
|
8
|
+
|
9
|
+
- allow temporary queues with amq.queue(nil) syntax (use uuids)
|
10
|
+
- use as temp queue in rpc
|
11
|
+
- use uuids for message ids in rpc
|
12
|
+
|
13
|
+
- add ack/completed responses for messages
|
14
|
+
- deleting queues/bindings/exchanges
|
15
|
+
+ queue.unbind
|
16
|
+
- queue.remove or queue.close or queue.delete
|
17
|
+
- exchange.remove
|
18
|
+
- rpc.remove
|
19
|
+
|
20
|
+
- handle errors and exceptions
|
21
|
+
binding to a non-existent (or not yet created in clock.rb) exchange
|
22
|
+
#<AMQP::Protocol::Channel::Close:0x11d35d4
|
23
|
+
@class_id=50,
|
24
|
+
@debug=1,
|
25
|
+
@method_id=20,
|
26
|
+
@reply_code=404,
|
27
|
+
@reply_text="NOT_FOUND - no exchange 'clock' in vhost '/'">>]
|
28
|
+
|
29
|
+
- handle connection.redirect during connect (for rabbitmq in distributed mode) [or just set insist to true]
|
30
|
+
|
31
|
+
- add amq.queue('name').size{ |num| "#{num} messages in the queue" } (send declare passive, look at declare-ok response)
|
32
|
+
- clean up MQ.default on disconnect
|
data/doc/EXAMPLE_05_ACK
ADDED
data/doc/EXAMPLE_05_POP
ADDED
@@ -1,13 +1,12 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
2
|
require 'mq'
|
3
|
-
require 'pp'
|
4
3
|
|
5
|
-
# For ack to work
|
4
|
+
# For ack to work appropriately you must shutdown AMQP gracefully,
|
6
5
|
# otherwise all items in your queue will be returned
|
7
6
|
Signal.trap('INT') { AMQP.stop{ EM.stop } }
|
8
7
|
Signal.trap('TERM'){ AMQP.stop{ EM.stop } }
|
9
8
|
|
10
|
-
|
9
|
+
AMQP.start(:host => 'localhost') do
|
11
10
|
MQ.queue('awesome').publish('Totally rad 1')
|
12
11
|
MQ.queue('awesome').publish('Totally rad 2')
|
13
12
|
MQ.queue('awesome').publish('Totally rad 3')
|
data/examples/mq/clock.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
2
|
require 'mq'
|
3
3
|
|
4
|
-
|
4
|
+
AMQP.start(:host => 'localhost') do
|
5
5
|
|
6
6
|
def log *args
|
7
7
|
p args
|
@@ -28,7 +28,7 @@ EM.run{
|
|
28
28
|
log 'every 5 seconds', :received, time if time.strftime('%S').to_i%5 == 0
|
29
29
|
}
|
30
30
|
|
31
|
-
|
31
|
+
end
|
32
32
|
|
33
33
|
__END__
|
34
34
|
|
data/examples/mq/hashtable.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
2
|
require 'mq'
|
3
3
|
|
4
|
-
|
4
|
+
AMQP.start(:host => 'localhost') do
|
5
5
|
|
6
6
|
def log *args
|
7
7
|
p args
|
@@ -37,10 +37,10 @@ EM.run{
|
|
37
37
|
client.set(:one, 1)
|
38
38
|
client.keys do |res|
|
39
39
|
log 'client', :keys => res
|
40
|
-
EM.
|
40
|
+
AMQP.stop{ EM.stop }
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
end
|
44
44
|
|
45
45
|
__END__
|
46
46
|
|
File without changes
|
data/examples/mq/logger.rb
CHANGED
@@ -4,7 +4,7 @@ require 'mq/logger'
|
|
4
4
|
|
5
5
|
Logger = MQ::Logger
|
6
6
|
|
7
|
-
|
7
|
+
AMQP.start(:host => 'localhost') do
|
8
8
|
if ARGV[0] == 'server'
|
9
9
|
|
10
10
|
MQ.queue('logger').bind(MQ.fanout('logging', :durable => true)).subscribe{|msg|
|
@@ -37,7 +37,7 @@ EM.run{
|
|
37
37
|
log = Logger.new(:webserver, :timestamp, :hostname, &log.printer)
|
38
38
|
log.info 'Request for /', :GET, :session => 'abc'
|
39
39
|
|
40
|
-
AMQP.stop{ EM.
|
40
|
+
AMQP.stop{ EM.stop }
|
41
41
|
|
42
42
|
else
|
43
43
|
|
@@ -50,7 +50,7 @@ EM.run{
|
|
50
50
|
EM.stop
|
51
51
|
|
52
52
|
end
|
53
|
-
|
53
|
+
end
|
54
54
|
|
55
55
|
__END__
|
56
56
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
require 'mq'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
AMQP.start(:host => 'localhost') do
|
6
|
+
|
7
|
+
def log *args
|
8
|
+
p args
|
9
|
+
end
|
10
|
+
|
11
|
+
#AMQP.logging = true
|
12
|
+
|
13
|
+
clock = MQ.new.headers('multiformat_clock')
|
14
|
+
EM.add_periodic_timer(1){
|
15
|
+
puts
|
16
|
+
|
17
|
+
time = Time.new
|
18
|
+
["iso8601","rfc2822"].each do |format|
|
19
|
+
formatted_time = time.send(format)
|
20
|
+
log :publish, format, formatted_time
|
21
|
+
clock.publish "#{formatted_time}", :headers => {"format" => format}
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
["iso8601","rfc2822"].each do |format|
|
26
|
+
amq = MQ.new
|
27
|
+
amq.queue(format.to_s).bind(amq.headers('multiformat_clock'), :arguments => {"format" => format}).subscribe{ |time|
|
28
|
+
log "received #{format}", time
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
__END__
|
35
|
+
|
36
|
+
[:publish, "iso8601", "2009-02-13T19:55:40-08:00"]
|
37
|
+
[:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:40 -0800"]
|
38
|
+
["received iso8601", "2009-02-13T19:55:40-08:00"]
|
39
|
+
["received rfc2822", "Fri, 13 Feb 2009 19:55:40 -0800"]
|
40
|
+
|
41
|
+
[:publish, "iso8601", "2009-02-13T19:55:41-08:00"]
|
42
|
+
[:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:41 -0800"]
|
43
|
+
["received iso8601", "2009-02-13T19:55:41-08:00"]
|
44
|
+
["received rfc2822", "Fri, 13 Feb 2009 19:55:41 -0800"]
|
45
|
+
|
46
|
+
[:publish, "iso8601", "2009-02-13T19:55:42-08:00"]
|
47
|
+
[:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:42 -0800"]
|
48
|
+
["received iso8601", "2009-02-13T19:55:42-08:00"]
|
49
|
+
["received rfc2822", "Fri, 13 Feb 2009 19:55:42 -0800"]
|
data/examples/mq/pingpong.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
2
|
require 'mq'
|
3
3
|
|
4
|
-
|
4
|
+
AMQP.start(:host => 'localhost') do
|
5
5
|
|
6
6
|
def log *args
|
7
7
|
p [ Time.now, *args ]
|
@@ -28,7 +28,7 @@ EM.run{
|
|
28
28
|
log 'two', :received, msg
|
29
29
|
}
|
30
30
|
|
31
|
-
|
31
|
+
end
|
32
32
|
|
33
33
|
__END__
|
34
34
|
|
File without changes
|
data/examples/mq/primes.rb
CHANGED
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
# spawn workers
|
13
13
|
workers = ARGV[0] ? (Integer(ARGV[0]) rescue 1) : 1
|
14
|
-
|
14
|
+
AMQP.fork(workers) do
|
15
15
|
|
16
16
|
log MQ.id, :started
|
17
17
|
|
@@ -33,7 +33,7 @@ EM.fork(workers) do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
# use workers to check which numbers are prime
|
36
|
-
|
36
|
+
AMQP.start(:host => 'localhost') do
|
37
37
|
|
38
38
|
prime_checker = MQ.rpc('prime checker')
|
39
39
|
|
@@ -52,7 +52,7 @@ EM.run{
|
|
52
52
|
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
end
|
56
56
|
|
57
57
|
__END__
|
58
58
|
|
data/examples/mq/stocks.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
2
|
require 'mq'
|
3
3
|
|
4
|
-
|
4
|
+
AMQP.start(:host => 'localhost') do
|
5
5
|
|
6
6
|
def log *args
|
7
7
|
p [ Time.now, *args ]
|
@@ -41,7 +41,7 @@ EM.run{
|
|
41
41
|
watch_appl_stock
|
42
42
|
watch_us_stocks
|
43
43
|
|
44
|
-
|
44
|
+
end
|
45
45
|
|
46
46
|
__END__
|
47
47
|
|
data/lib/amqp.rb
CHANGED
data/lib/amqp/client.rb
CHANGED
@@ -65,7 +65,7 @@ module AMQP
|
|
65
65
|
@on_disconnect ||= proc{ raise Error, "Could not connect to server #{opts[:host]}:#{opts[:port]}" }
|
66
66
|
|
67
67
|
timeout @settings[:timeout] if @settings[:timeout]
|
68
|
-
errback{ @on_disconnect.call }
|
68
|
+
errback{ @on_disconnect.call } unless @reconnecting
|
69
69
|
end
|
70
70
|
|
71
71
|
def connection_completed
|
@@ -158,14 +158,14 @@ module AMQP
|
|
158
158
|
end
|
159
159
|
|
160
160
|
unless @reconnecting
|
161
|
+
@reconnecting = true
|
162
|
+
|
161
163
|
@deferred_status = nil
|
162
164
|
initialize(@settings)
|
163
165
|
|
164
166
|
mqs = @channels
|
165
167
|
@channels = {}
|
166
168
|
mqs.each{ |_,mq| mq.reset } if mqs
|
167
|
-
|
168
|
-
@reconnecting = true
|
169
169
|
end
|
170
170
|
|
171
171
|
log 'reconnecting'
|
@@ -186,4 +186,4 @@ module AMQP
|
|
186
186
|
puts
|
187
187
|
end
|
188
188
|
end
|
189
|
-
end
|
189
|
+
end
|
data/lib/amqp/server.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'amqp/frame'
|
2
|
+
|
3
|
+
module AMQP
|
4
|
+
module Server
|
5
|
+
def post_init
|
6
|
+
@buf = ''
|
7
|
+
@channels = {}
|
8
|
+
@started = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def receive_data data
|
12
|
+
@buf << data
|
13
|
+
|
14
|
+
unless @started
|
15
|
+
if @buf.size >= 8
|
16
|
+
if @buf.slice!(0,8) == "AMQP\001\001\b\000"
|
17
|
+
send Protocol::Connection::Start.new(
|
18
|
+
8,
|
19
|
+
0,
|
20
|
+
{
|
21
|
+
:information => 'Licensed under the Ruby license. See http://github.com/tmm1/amqp',
|
22
|
+
:copyright => 'Copyright (c) 2008-2009 Aman Gupta',
|
23
|
+
:platform => 'Ruby/EventMachine',
|
24
|
+
:version => '0.6.1',
|
25
|
+
:product => 'SquirrelMQ'
|
26
|
+
},
|
27
|
+
'PLAIN AMQPLAIN',
|
28
|
+
'en_US'
|
29
|
+
)
|
30
|
+
else
|
31
|
+
close_connection
|
32
|
+
return
|
33
|
+
end
|
34
|
+
@started = true
|
35
|
+
else
|
36
|
+
return
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
while frame = Frame.parse(@buf)
|
41
|
+
process_frame frame
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_frame frame
|
46
|
+
channel = frame.channel
|
47
|
+
|
48
|
+
case method = frame.payload
|
49
|
+
when Protocol::Connection::StartOk
|
50
|
+
@user = method.response[:LOGIN]
|
51
|
+
@pass = method.response[:PASSWORD]
|
52
|
+
send Protocol::Connection::Tune.new(0, 131072, 0)
|
53
|
+
|
54
|
+
when Protocol::Connection::TuneOk
|
55
|
+
# mnnk
|
56
|
+
|
57
|
+
when Protocol::Connection::Open
|
58
|
+
@vhost = method.virtual_host
|
59
|
+
send Protocol::Connection::OpenOk.new('localhost')
|
60
|
+
|
61
|
+
when Protocol::Channel::Open
|
62
|
+
@channels[channel] = []
|
63
|
+
send Protocol::Channel::OpenOk.new, :channel => channel
|
64
|
+
|
65
|
+
when Protocol::Access::Request
|
66
|
+
send Protocol::Access::RequestOk.new(101)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def send data, opts = {}
|
71
|
+
channel = opts[:channel] ||= 0
|
72
|
+
data = data.to_frame(channel) unless data.is_a? Frame
|
73
|
+
data.channel = channel
|
74
|
+
|
75
|
+
log 'send', data
|
76
|
+
send_data data.to_s
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.start host = 'localhost', port = 5672
|
80
|
+
EM.start_server host, port, self
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def log *args
|
86
|
+
require 'pp'
|
87
|
+
pp args
|
88
|
+
puts
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if __FILE__ == $0
|
94
|
+
require 'rubygems'
|
95
|
+
require 'eventmachine'
|
96
|
+
EM.run{
|
97
|
+
AMQP::Server.start
|
98
|
+
}
|
99
|
+
end
|