amqp 0.7.5 → 0.8.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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