amqp 0.7.5 → 0.8.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. data/.gitignore +3 -4
  2. data/.travis.yml +3 -5
  3. data/.yardopts +6 -0
  4. data/CHANGELOG +26 -7
  5. data/Gemfile +15 -7
  6. data/README.textile +216 -0
  7. data/Rakefile +0 -6
  8. data/amqp.gemspec +14 -4
  9. data/bin/jenkins.sh +27 -0
  10. data/bin/set_test_suite_realms_up.sh +16 -2
  11. data/docs/VendorSpecificExtensions.textile +32 -0
  12. data/examples/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb +53 -0
  13. data/examples/hello_world.rb +29 -0
  14. data/examples/real-world/task-queue/README.textile +3 -0
  15. data/examples/real-world/task-queue/consumer.rb +27 -0
  16. data/examples/real-world/task-queue/producer.rb +22 -0
  17. data/examples/various/ack.rb +70 -0
  18. data/examples/various/automatic_binding_for_default_direct_exchange.rb +53 -0
  19. data/examples/various/basic_get.rb +65 -0
  20. data/examples/various/callbacks.rb +45 -0
  21. data/examples/various/clock.rb +74 -0
  22. data/examples/various/declare_a_queue_without_assignment.rb +46 -0
  23. data/examples/various/declare_an_exchange_without_assignment.rb +46 -0
  24. data/examples/various/hashtable.rb +60 -0
  25. data/examples/{logger.rb → various/logger.rb} +9 -7
  26. data/examples/{multiclock.rb → various/multiclock.rb} +15 -17
  27. data/examples/various/open_channel_without_assignment.rb +34 -0
  28. data/examples/various/pingpong.rb +53 -0
  29. data/examples/various/primes-simple.rb +29 -0
  30. data/examples/various/primes.rb +76 -0
  31. data/examples/various/pubsub.rb +43 -0
  32. data/examples/various/queue_status.rb +58 -0
  33. data/examples/various/stocks.rb +59 -0
  34. data/examples/various/weather_updates.rb +63 -0
  35. data/lib/amqp.rb +11 -2
  36. data/lib/amqp/basic_client.rb +23 -54
  37. data/lib/amqp/channel.rb +577 -805
  38. data/lib/amqp/client.rb +37 -275
  39. data/lib/amqp/connection.rb +165 -93
  40. data/lib/amqp/deprecated/fork.rb +15 -0
  41. data/lib/amqp/deprecated/logger.rb +99 -0
  42. data/lib/amqp/deprecated/mq.rb +20 -0
  43. data/lib/amqp/deprecated/rpc.rb +168 -0
  44. data/lib/amqp/exchange.rb +409 -281
  45. data/lib/amqp/extensions/rabbitmq.rb +1 -0
  46. data/lib/amqp/header.rb +41 -17
  47. data/lib/amqp/logger.rb +10 -84
  48. data/lib/amqp/queue.rb +457 -320
  49. data/lib/amqp/rpc.rb +11 -107
  50. data/lib/amqp/version.rb +1 -1
  51. data/lib/mq.rb +2 -1
  52. data/lib/mq/logger.rb +2 -0
  53. data/lib/mq/rpc.rb +2 -0
  54. data/spec/integration/authentication_spec.rb +36 -40
  55. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +3 -5
  56. data/spec/integration/basic_get_spec.rb +91 -0
  57. data/spec/integration/channel_close_spec.rb +5 -5
  58. data/spec/integration/exchange_declaration_spec.rb +6 -53
  59. data/spec/integration/extensions/basic_return_spec.rb +47 -0
  60. data/spec/integration/queue_declaration_spec.rb +14 -17
  61. data/spec/integration/queue_exclusivity_spec.rb +49 -48
  62. data/spec/integration/reply_queue_communication_spec.rb +6 -4
  63. data/spec/integration/store_and_forward_spec.rb +9 -36
  64. data/spec/integration/topic_subscription_spec.rb +1 -1
  65. data/spec/integration/workload_distribution_spec.rb +1 -0
  66. data/spec/spec_helper.rb +69 -43
  67. data/spec/unit/amqp/connection_spec.rb +27 -23
  68. data/tasks.rb +11 -0
  69. metadata +124 -95
  70. data/README.md +0 -156
  71. data/TODO +0 -30
  72. data/amqp.pre.gemspec +0 -6
  73. data/examples/ack.rb +0 -47
  74. data/examples/automatic_binding_for_default_direct_exchange.rb +0 -65
  75. data/examples/callbacks.rb +0 -40
  76. data/examples/clock.rb +0 -65
  77. data/examples/default_channel.rb +0 -19
  78. data/examples/hashtable.rb +0 -61
  79. data/examples/immediately_bind_a_server_named_queue.rb +0 -38
  80. data/examples/internal.rb +0 -51
  81. data/examples/issues/issue_75.rb +0 -21
  82. data/examples/issues/issue_94.rb +0 -23
  83. data/examples/pingpong.rb +0 -54
  84. data/examples/pop.rb +0 -45
  85. data/examples/primes-simple.rb +0 -21
  86. data/examples/primes.rb +0 -101
  87. data/examples/simple.rb +0 -81
  88. data/examples/stocks.rb +0 -67
  89. data/gemfiles/eventmachine-pre +0 -24
  90. data/lib/amqp/buffer.rb +0 -272
  91. data/lib/amqp/collection.rb +0 -60
  92. data/lib/amqp/frame.rb +0 -68
  93. data/lib/amqp/protocol.rb +0 -163
  94. data/lib/amqp/server.rb +0 -101
  95. data/lib/amqp/spec.rb +0 -832
  96. data/protocol/amqp-0.8.json +0 -617
  97. data/protocol/amqp-0.8.xml +0 -3908
  98. data/protocol/codegen.rb +0 -175
  99. data/protocol/doc.txt +0 -281
  100. data/research/api.rb +0 -52
  101. data/research/primes-forked.rb +0 -65
  102. data/research/primes-processes.rb +0 -137
  103. data/research/primes-threaded.rb +0 -51
  104. data/spec/integration/queue_status_spec.rb +0 -44
  105. data/spec/unit/amqp/buffer_spec.rb +0 -178
  106. data/spec/unit/amqp/client_spec.rb +0 -102
  107. data/spec/unit/amqp/collection_spec.rb +0 -144
  108. data/spec/unit/amqp/frame_spec.rb +0 -60
  109. data/spec/unit/amqp/protocol_spec.rb +0 -51
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+
7
+ $:.unshift(File.expand_path("../../../../lib", __FILE__))
8
+ require 'amqp'
9
+ require "amqp/extensions/rabbitmq"
10
+
11
+ AMQP.start do |connection|
12
+ puts "Connected!"
13
+ AMQP::Channel.new(connection) do |channel|
14
+ puts "Channel #{channel.id} is now open"
15
+
16
+ channel.confirmations
17
+ channel.on_error do
18
+ puts "Oops, there is a channel-levle exceptions!"
19
+ end
20
+
21
+
22
+ channel.confirm do |basic_ack|
23
+ puts "Received basic_ack: multiple = #{basic_ack.multiple}, delivery_tag = #{basic_ack.delivery_tag}"
24
+ end
25
+
26
+ x = channel.fanout("amq.fanout")
27
+ channel.queue("", :auto_delete => true) do |q|
28
+ puts "Declared a new server-named qeueue: #{q.name}"
29
+
30
+ q.bind(x, :no_ack => true).subscribe(:ack => true) do |header, payload|
31
+ puts "Received #{payload}"
32
+ end
33
+ end
34
+
35
+ EventMachine.add_timer(0.5) do
36
+ 10.times do |i|
37
+ puts "Publishing message ##{i}"
38
+ x.publish("Message ##{i}")
39
+ end
40
+ end
41
+ end
42
+
43
+ show_stopper = Proc.new {
44
+ AMQP.stop do
45
+ EM.stop
46
+ end
47
+ }
48
+
49
+
50
+ EM.add_timer(3, show_stopper)
51
+ Signal.trap('INT', show_stopper)
52
+ Signal.trap('TERM', show_stopper)
53
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+
7
+ $:.unshift(File.expand_path("../../lib", __FILE__))
8
+
9
+ require 'amqp'
10
+
11
+ EventMachine.run do
12
+ AMQP.connect(:host => 'localhost') do |connection|
13
+ puts "Connected to AMQP broker"
14
+
15
+ channel = AMQP::Channel.new(connection)
16
+ queue = channel.queue("amqpgem.examples.hello_world")
17
+ exchange = channel.default_exchange
18
+
19
+ queue.subscribe do |payload|
20
+ puts "Received a message: #{payload}. Disconnecting..."
21
+
22
+ connection.close {
23
+ EM.stop { exit }
24
+ }
25
+ end
26
+
27
+ exchange.publish "Hello, world!", :routing_key => queue.name
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ h1. Task Queue
2
+
3
+ In task queue we have only one queue with many consumers (for example servers which will run given task)
@@ -0,0 +1,27 @@
1
+ # encoding: utf - 8
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
4
+
5
+ require "amqp"
6
+
7
+ # Imagine we have for example 10 servers, on each of them runs this
8
+ # script, just the server_name variable will be different on each of them.
9
+ server_name = "server - 1"
10
+
11
+ AMQP.start do
12
+ amq = AMQP::Channel.new
13
+
14
+ # Tasks distribution has to be based on load on each clients rather
15
+ # than on the number of distributed messages. (The default behaviour
16
+ # is to dispatches every n - th message to the n - th consumer.
17
+ amq.prefetch(1)
18
+
19
+ # Acknowledgements are good for letting the server know
20
+ # that the task is finished. If the consumer doesn't send
21
+ # the acknowledgement, then the task is considered to be unfinished.
22
+ amq.queue(server_name).subscribe(:ack => true) do |h, message|
23
+ puts message
24
+ puts system(message)
25
+ h.ack
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf - 8
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
4
+
5
+ require "amqp"
6
+
7
+ # Imagine the command is something
8
+ # CPU - intensive like image processing.
9
+ command = "sleep 0.1"
10
+
11
+ AMQP.start(port: 1112) do
12
+ amq = AMQP::Channel.new
13
+ exchange = amq.direct("tasks")
14
+ queue = amq.queue("tasks")
15
+
16
+ # And this is user - input simulation,
17
+ # which can be a user uploading an image.
18
+ EM.add_periodic_timer(1) do
19
+ puts "~ publishing # {command}"
20
+ exchange.publish(command, :routing_key => "tasks")
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+
7
+ $:.unshift(File.expand_path("../../../lib", __FILE__))
8
+ require 'amqp'
9
+
10
+
11
+ AMQP.start do |connection|
12
+ puts "Connected!"
13
+ channel = AMQP::Channel.new(connection)
14
+ e = channel.fanout("amqp-gem.examples.ack")
15
+ q = channel.queue('amqp-gem.examples.q1').bind(e) { puts "Bound #{e.name} to the queue" }
16
+
17
+ q.status do |message_count, consumer_count|
18
+ puts "Queue #{q.name} has #{message_count} messages and #{consumer_count} consumers"
19
+ end
20
+
21
+ i = 0
22
+
23
+ # Stopping after the second item was acked will keep the 3rd item in the queue
24
+ q.subscribe(:ack => true) do |h, m|
25
+ puts "Got a message"
26
+
27
+ if AMQP.closing?
28
+ puts "#{m} (ignored, redelivered later)"
29
+ else
30
+ puts m
31
+ h.ack
32
+ end
33
+ end # channel.queue
34
+
35
+
36
+ 10.times do |i|
37
+ puts "Publishing message ##{i}"
38
+ e.publish("Totally rad #{i}")
39
+ end
40
+
41
+
42
+ show_stopper = Proc.new {
43
+ q.status do |message_count, consumer_count|
44
+ puts "Queue #{q.name} has #{message_count} messages and #{consumer_count} consumers"
45
+ end
46
+
47
+ q.unbind(e) do
48
+ puts "Unbound #{q.name} from #{e.name}"
49
+
50
+ e.delete do
51
+ puts "Just deleted #{e.name}"
52
+ end
53
+
54
+ q.delete do
55
+ puts "Just deleted #{q.name}"
56
+ AMQP.stop do
57
+ puts "About to stop EM reactor"
58
+ EM.stop
59
+ end
60
+ end
61
+ end
62
+ }
63
+
64
+ EM.add_timer(3, show_stopper)
65
+
66
+ # For ack to work appropriately you must shutdown AMQP gracefully,
67
+ # otherwise all items in your queue will be returned
68
+ Signal.trap('INT', show_stopper)
69
+ Signal.trap('TERM', show_stopper)
70
+ end # AMQP.start
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+
7
+ $:.unshift(File.expand_path("../../../lib", __FILE__))
8
+
9
+ require 'amqp'
10
+
11
+ if RUBY_VERSION == "1.8.7"
12
+ class Array
13
+ alias sample choice
14
+ end
15
+ end
16
+
17
+ puts "=> Default exchange example"
18
+ puts
19
+ AMQP.start(:host => 'localhost') do |connection|
20
+ ch = AMQP::Channel.new(connection)
21
+
22
+ queue1 = ch.queue("queue1").subscribe do |payload|
23
+ puts "[#{queue1.name}] => #{payload}"
24
+ end
25
+ queue2 = ch.queue("queue2").subscribe do |payload|
26
+ puts "[#{queue2.name}] => #{payload}"
27
+ end
28
+ queue3 = ch.queue("queue3").subscribe do |payload|
29
+ puts "[#{queue3.name}] => #{payload}"
30
+ end
31
+ queues = [queue1, queue2, queue3]
32
+
33
+ # Rely on default direct exchange binding, see section 2.1.2.4 Automatic Mode in AMQP 0.9.1 spec.
34
+ exchange = AMQP::Exchange.default
35
+ EM.add_periodic_timer(1) do
36
+ q = queues.sample
37
+
38
+ $stdout.puts "Publishing to default exchange with routing key = #{q.name}..."
39
+ exchange.publish "Some payload from #{Time.now.to_i}", :routing_key => q.name
40
+ end
41
+
42
+
43
+ show_stopper = Proc.new do
44
+ $stdout.puts "Stopping..."
45
+ connection.close {
46
+ EM.stop { exit }
47
+ }
48
+ end
49
+
50
+ Signal.trap "INT", &show_stopper
51
+ Signal.trap "TERM", &show_stopper
52
+ EM.add_timer(7, show_stopper)
53
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+
7
+ $:.unshift(File.expand_path("../../../lib", __FILE__))
8
+
9
+ require 'amqp'
10
+
11
+ if RUBY_VERSION == "1.8.7"
12
+ class Array
13
+ alias sample choice
14
+ end
15
+ end
16
+
17
+
18
+ puts "=> basic.get example"
19
+ puts
20
+ AMQP.start(:host => 'localhost') do |connection|
21
+ channel = AMQP::Channel.new
22
+
23
+ queue_name = "amqpgem.integration.basic.get.queue"
24
+ expected_number_of_messages = 50
25
+
26
+ exchange = channel.fanout("amqpgem.integration.basic.get.fanout", :auto_delete => true)
27
+ queue = channel.queue(queue_name, :auto_delete => true)
28
+
29
+ queue.bind(exchange) do
30
+ puts "Bound #{exchange.name} => #{queue.name}"
31
+ end
32
+ expected_number_of_messages.times do |i|
33
+ print "."
34
+ exchange.publish(Time.now.to_i.to_s + "_#{i}", :key => queue_name)
35
+ end
36
+ $stdout.flush
37
+
38
+ sleep 1
39
+
40
+ queue.status do |number_of_messages, number_of_consumers|
41
+ puts "# of messages on status = #{number_of_messages}"
42
+ end
43
+
44
+ queue.status do |number_of_messages, number_of_consumers|
45
+ puts "# of messages on status = #{number_of_messages}"
46
+ expected_number_of_messages.times do
47
+ queue.pop do |headers, payload|
48
+ puts "=> With payload #{payload.inspect}, routing key: #{headers.routing_key}, #{headers.message_count} message(s) left in the queue"
49
+ end # pop
50
+ end
51
+ end
52
+
53
+
54
+ show_stopper = Proc.new do
55
+ $stdout.puts "Stopping..."
56
+ # now change this to just EM.stop and it
57
+ # unbinds instantly
58
+ connection.close {
59
+ EM.stop { exit }
60
+ }
61
+ end
62
+
63
+ Signal.trap "INT", show_stopper
64
+ EM.add_timer(2, show_stopper)
65
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+
7
+ $:.unshift File.expand_path("../../lib", __FILE__)
8
+ require "amqp"
9
+
10
+ AMQP.start(:host => "localhost") do |connection|
11
+
12
+ # Send Connection.Close on Ctrl+C
13
+ trap(:INT) do
14
+ unless connection.closing?
15
+ connection.close { exit! }
16
+ end
17
+ end
18
+
19
+ @counter = 0
20
+ amq = AMQP::Channel.new
21
+
22
+ amq.prefetch(64, false) do
23
+ puts "basic.qos callback has fired"
24
+ end
25
+
26
+ amq.recover do
27
+ puts "basic.recover callback has fired"
28
+ end
29
+
30
+ 10.times do
31
+ amq.queue("") do |queue|
32
+ puts "Queue #{queue.name} is now declared."
33
+ puts "All queues: #{amq.queues.map { |q| q.name }.join(', ')}"
34
+
35
+ @counter += 1
36
+ end
37
+ end
38
+
39
+ EM.add_timer(0.3) do
40
+ connection.disconnect do
41
+ puts "AMQP connection is now closed."
42
+ EM.stop
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require "bundler"
5
+ Bundler.setup
6
+ Bundler.require :default
7
+
8
+ $:.unshift(File.expand_path("../../../lib", __FILE__))
9
+ require 'amqp'
10
+
11
+ puts "=> Clock example"
12
+ puts
13
+ AMQP.start(:host => 'localhost') do |connection|
14
+ puts "Connected!"
15
+
16
+ def log(*args)
17
+ p args
18
+ end
19
+
20
+ # AMQP.logging = true
21
+
22
+ channel = AMQP::Channel.new(connection)
23
+ puts "Channel #{channel.id} is now open"
24
+ producer = channel.fanout('clock')
25
+ EM.add_periodic_timer(1) {
26
+ puts
27
+
28
+ log :publishing, time = Time.now
29
+ producer.publish(Marshal.dump(time))
30
+ }
31
+
32
+ channel2 = AMQP::Channel.new(connection)
33
+ exchange = channel2.fanout('clock')
34
+
35
+ q1 = channel2.queue('every second')
36
+ q1.bind(exchange).subscribe(:confirm => proc { puts "Subscribed!" }) { |time|
37
+ log 'every second', :received, Marshal.load(time)
38
+ }
39
+
40
+ puts "channel #{channel2.id} consumer tags: #{channel2.consumers.keys.join(', ')}"
41
+
42
+ # channel3 = AMQP::Channel.new
43
+ channel3 = AMQP::Channel.new(connection)
44
+ q2 = channel3.queue('every 5 seconds')
45
+ q2.bind(exchange).subscribe { |time|
46
+ time = Marshal.load(time)
47
+ log 'every 5 seconds', :received, time if time.strftime('%S').to_i % 5 == 0
48
+ }
49
+
50
+ show_stopper = Proc.new {
51
+ q1.unbind(exchange)
52
+ q2.unbind(exchange) do
53
+ puts "Unbound #{q2.name}."
54
+
55
+ q1.purge do |message_count|
56
+ puts "Purged #{q1.name}, there were #{message_count} messages"
57
+ puts "Deleting #{q1.name}…"
58
+ q1.delete(:if_empty => true, :nowait => true)
59
+ end
60
+
61
+ q2.delete do |message_count|
62
+ puts "Deleted #{q2.name}. There were #{message_count} messages"
63
+ end
64
+
65
+ puts " About to close AMQP connection…"
66
+ connection.close { exit! } unless connection.closing?
67
+ end
68
+ }
69
+
70
+ Signal.trap "INT", show_stopper
71
+ Signal.trap "TERM", show_stopper
72
+
73
+ EM.add_timer(7, show_stopper)
74
+ end