amqp 0.8.0.rc13 → 0.8.0.rc14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.rspec +2 -1
  2. data/.travis.yml +8 -2
  3. data/.yardopts +1 -0
  4. data/CHANGELOG +9 -0
  5. data/Gemfile +17 -11
  6. data/README.md +26 -16
  7. data/amqp.gemspec +2 -2
  8. data/bin/ci/before_build.sh +21 -0
  9. data/docs/08Migration.textile +199 -5
  10. data/docs/AMQP091ModelExplained.textile +322 -0
  11. data/docs/Bindings.textile +24 -4
  12. data/docs/Clustering.textile +1 -1
  13. data/docs/ConnectingToTheBroker.textile +98 -82
  14. data/docs/ConnectionEncryptionWithTLS.textile +65 -5
  15. data/docs/DocumentationGuidesIndex.textile +93 -13
  16. data/docs/Durability.textile +1 -1
  17. data/docs/ErrorHandling.textile +458 -94
  18. data/docs/Exchanges.textile +901 -87
  19. data/docs/GettingStarted.textile +278 -143
  20. data/docs/PatternsAndUseCases.textile +420 -0
  21. data/docs/Queues.textile +730 -178
  22. data/docs/RabbitMQVersions.textile +18 -3
  23. data/docs/RunningTests.textile +1 -1
  24. data/docs/TestingWithEventedSpec.textile +121 -0
  25. data/docs/Troubleshooting.textile +15 -1
  26. data/docs/VendorSpecificExtensions.textile +1 -1
  27. data/docs/diagrams/001_hello_world_example_routing.png +0 -0
  28. data/docs/diagrams/002_blabbr_example_routing.png +0 -0
  29. data/docs/diagrams/003_weathr_example_routing.png +0 -0
  30. data/docs/diagrams/004_fanout_exchange.png +0 -0
  31. data/docs/diagrams/005_direct_exchange.png +0 -0
  32. data/docs/diagrams/redhat/direct_exchange.png +0 -0
  33. data/docs/diagrams/redhat/fanout_exchange.png +0 -0
  34. data/docs/diagrams/redhat/topic_exchange.png +0 -0
  35. data/examples/error_handling/automatic_recovery_of_channel_and_queues.rb +50 -0
  36. data/examples/error_handling/automatically_recovering_hello_world_consumer.rb +51 -0
  37. data/examples/error_handling/automatically_recovering_hello_world_consumer_that_uses_a_server_named_queue.rb +51 -0
  38. data/examples/error_handling/basic_connection_failover.rb +22 -0
  39. data/examples/error_handling/channel_level_exception.rb +9 -2
  40. data/examples/error_handling/connection_level_exception.rb +8 -1
  41. data/examples/error_handling/connection_level_exception_with_objects.rb +49 -0
  42. data/examples/error_handling/connection_loss_handler.rb +1 -5
  43. data/examples/error_handling/hello_world_producer.rb +43 -0
  44. data/examples/error_handling/insufficient_permissions.rb +54 -0
  45. data/examples/error_handling/manual_connection_and_channel_recovery.rb +71 -0
  46. data/examples/error_handling/queue_exclusivity_violation.rb +41 -0
  47. data/examples/error_handling/queue_name_violation.rb +31 -0
  48. data/examples/exchanges/autodeletion_of_exchanges.rb +1 -4
  49. data/examples/guides/queues/01a_declaring_a_server_named_queue_using_queue_constructor.rb +7 -8
  50. data/examples/guides/queues/01b_declaring_a_queue_using_queue_constructor.rb +7 -8
  51. data/examples/guides/queues/02a_declaring_a_durable_shared_queue.rb +5 -8
  52. data/examples/guides/queues/02b_declaring_a_durable_shared_queue.rb +5 -8
  53. data/examples/guides/queues/03a_declaring_a_temporary_exclusive_queue.rb +7 -8
  54. data/examples/guides/queues/04_bind_a_queue_using_exchange_instance.rb +9 -10
  55. data/examples/guides/queues/05_bind_a_queue_using_exchange_name.rb +8 -10
  56. data/examples/guides/queues/06_subscribe_to_receive_messages.rb +10 -12
  57. data/examples/guides/queues/07_fetch_a_message_from_the_queue.rb +14 -14
  58. data/examples/guides/queues/08_unsubscribing_a_consumer.rb +13 -16
  59. data/examples/guides/queues/09_unbinding_from_exchange.rb +16 -22
  60. data/examples/guides/queues/10_purge_a_queue.rb +13 -18
  61. data/examples/guides/queues/11_deleting_a_queue.rb +14 -19
  62. data/examples/guides/queues/12_objects_that_consume_messages.rb +69 -0
  63. data/examples/guides/queues/13_objects_that_consume_messages_take_two.rb +89 -0
  64. data/examples/hello_world.rb +1 -3
  65. data/examples/hello_world_with_an_empty_string.rb +5 -6
  66. data/examples/inspecting_server_information.rb +45 -0
  67. data/examples/issues/issue_93.rb +23 -0
  68. data/examples/issues/issue_94.rb +23 -0
  69. data/examples/patterns/command/consumer.rb +45 -0
  70. data/examples/patterns/command/producer.rb +26 -0
  71. data/examples/patterns/request_reply/client.rb +29 -0
  72. data/examples/patterns/request_reply/server.rb +26 -0
  73. data/examples/publishing/publishing_a_one_off_message.rb +6 -4
  74. data/examples/publishing/returned_messages.rb +2 -10
  75. data/examples/queues/accessing_message_metadata.rb +15 -13
  76. data/examples/queues/queue_status.rb +12 -15
  77. data/examples/routing/fanout_routing.rb +33 -0
  78. data/examples/routing/headers_routing.rb +17 -15
  79. data/examples/routing/round_robin_with_direct_exchange.rb +39 -0
  80. data/examples/routing/round_robin_with_the_default_exchange.rb +38 -0
  81. data/examples/routing/unroutable_mandatory_message_is_returned.rb +33 -0
  82. data/examples/routing/weather_updates.rb +15 -20
  83. data/examples/tls/using_tls.rb +41 -0
  84. data/lib/amqp/bit_set.rb +80 -0
  85. data/lib/amqp/broker.rb +72 -0
  86. data/lib/amqp/channel.rb +93 -13
  87. data/lib/amqp/client.rb +11 -22
  88. data/lib/amqp/compatibility/ruby187_patchlevel_check.rb +2 -0
  89. data/lib/amqp/connection.rb +2 -3
  90. data/lib/amqp/consumer.rb +208 -0
  91. data/lib/amqp/deprecated/fork.rb +2 -0
  92. data/lib/amqp/deprecated/mq.rb +2 -0
  93. data/lib/amqp/exchange.rb +6 -4
  94. data/lib/amqp/extensions/rabbitmq.rb +3 -1
  95. data/lib/amqp/header.rb +76 -14
  96. data/lib/amqp/int_allocator.rb +96 -0
  97. data/lib/amqp/logger.rb +2 -0
  98. data/lib/amqp/queue.rb +242 -86
  99. data/lib/amqp/rpc.rb +2 -0
  100. data/lib/amqp/session.rb +169 -9
  101. data/lib/amqp/utilities/event_loop_helper.rb +2 -0
  102. data/lib/amqp/utilities/server_type.rb +2 -0
  103. data/lib/amqp/version.rb +2 -2
  104. data/lib/mq.rb +4 -2
  105. data/lib/mq/logger.rb +3 -1
  106. data/lib/mq/rpc.rb +3 -1
  107. data/spec/integration/authentication_spec.rb +17 -10
  108. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +1 -1
  109. data/spec/integration/automatic_recovery_predicate_spec.rb +68 -0
  110. data/spec/integration/basic_get_spec.rb +2 -1
  111. data/spec/integration/{extensions/basic_return_spec.rb → basic_return_spec.rb} +2 -1
  112. data/spec/integration/channel_level_exception_handling_spec.rb +53 -0
  113. data/spec/integration/connection_level_exception_handling_spec.rb +49 -0
  114. data/spec/integration/declare_and_immediately_bind_a_server_named_queue_spec.rb +38 -17
  115. data/spec/integration/declare_one_hundred_server_named_queues_spec.rb +44 -0
  116. data/spec/integration/direct_exchange_routing_spec.rb +125 -0
  117. data/spec/integration/exchange_declaration_spec.rb +75 -46
  118. data/spec/integration/extensions/rabbitmq/publisher_confirmations_spec.rb +180 -0
  119. data/spec/integration/{workload_distribution_spec.rb → fanout_exchange_routing_spec.rb} +10 -9
  120. data/spec/integration/headers_exchange_routing_spec.rb +269 -0
  121. data/spec/integration/hello_world_spec.rb +77 -0
  122. data/spec/integration/immediate_messages_spec.rb +59 -0
  123. data/spec/integration/mandatory_messages_spec.rb +52 -0
  124. data/spec/integration/message_metadata_access_spec.rb +106 -0
  125. data/spec/integration/multiple_consumers_per_queue_spec.rb +319 -0
  126. data/spec/integration/ordering_of_published_messages_spec.rb +96 -0
  127. data/spec/integration/queue_declaration_spec.rb +8 -8
  128. data/spec/integration/queue_status_spec.rb +66 -0
  129. data/spec/integration/recovery/per_channel_automatic_recovery_on_graceful_broker_shutdown_spec.rb +76 -0
  130. data/spec/integration/recovery/per_channel_automatic_recovery_spec.rb +72 -0
  131. data/spec/integration/redelivery_of_unacknowledged_messages_spec.rb +96 -0
  132. data/spec/integration/regressions/concurrent_publishing_on_the_same_channel_spec.rb +91 -0
  133. data/spec/integration/regressions/empty_message_body_spec.rb +56 -0
  134. data/spec/integration/regressions/issue66_spec.rb +2 -1
  135. data/spec/integration/reply_queue_communication_spec.rb +2 -1
  136. data/spec/integration/store_and_forward_spec.rb +4 -3
  137. data/spec/integration/topic_subscription_spec.rb +2 -1
  138. data/spec/integration/tx_commit_spec.rb +124 -0
  139. data/spec/integration/tx_rollback_spec.rb +167 -0
  140. data/spec/spec_helper.rb +44 -71
  141. data/spec/unit/amqp/bit_set_spec.rb +127 -0
  142. data/spec/unit/amqp/channel_id_allocation_spec.rb +40 -0
  143. data/spec/unit/amqp/connection_spec.rb +4 -2
  144. data/spec/unit/amqp/int_allocator_spec.rb +116 -0
  145. metadata +92 -26
  146. data/CONTRIBUTORS +0 -29
  147. data/docs/Routing.textile +0 -30
  148. data/examples/real-world/task-queue/README.textile +0 -3
  149. data/examples/real-world/task-queue/consumer.rb +0 -27
  150. data/examples/real-world/task-queue/producer.rb +0 -22
  151. data/spec/unit/amqp/basic_spec.rb +0 -39
  152. data/tasks.rb +0 -4
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ include PlatformDetection
6
+
7
+ # Only run this for MRI.
8
+ #
9
+ # rubinius implementation of ThreadGroup has a bug: it references objects without checking
10
+ # whether they are alive. So sandbox this test for other Rubies for now. Per discussion with
11
+ # brixen in #travis, see also https://gist.github.com/1100572.
12
+ #
13
+ # JRuby is having weird CI issues, too. Still investigating them. MK.
14
+ if mri?
15
+ describe "Concurrent publishing on a shared channel from multiple threads" do
16
+
17
+ #
18
+ # Environment
19
+ #
20
+
21
+ include EventedSpec::AMQPSpec
22
+ default_options AMQP_OPTS
23
+ default_timeout 15
24
+
25
+ amqp_before do
26
+ @channel = AMQP::Channel.new
27
+ @channel.on_error do |ch, close|
28
+ raise "Channel-level error!: #{close.inspect}"
29
+ end
30
+ @channel.connection.on_error do |conn, connection_close|
31
+ raise "Handling a connection-level exception: #{connection_close.reply_text}"
32
+ end
33
+ end
34
+
35
+
36
+ let(:inputs) do
37
+ [
38
+ { :index=>{:_routing=>530,:_index=>"optimizer",:_type=>"earnings",:_id=>530}},
39
+ { :total_conversions=>0,:banked_clicks=>0,:total_earnings=>0,:pending_conversions=>0,:paid_net_earnings=>0,:banked_conversions=>0,:pending_earnings=>0,:optimizer_id=>530,:total_impressions=>0,:banked_earnings=>0,:bounce_count=>0,:time_on_page=>0,:total_clicks=>0,:entrances=>0,:pending_clicks=>0,:paid_earnings=>0},
40
+
41
+ { :index=>{:_routing=>430,:_index=>"optimizer",:_type=>"earnings",:_id=>430}},
42
+ { :total_conversions=>1443,:banked_clicks=>882,:total_earnings=>5796.3315841537,:pending_conversions=>22,:paid_net_earnings=>4116.90224486802,:banked_conversions=>1086,:pending_earnings=>257.502767857143,:optimizer_id=>430,:total_impressions=>6370497,:banked_earnings=>122.139339285714,:bounce_count=>6825,:time_on_page=>0,:total_clicks=>38143,:entrances=>12336,:pending_clicks=>1528,:paid_earnings=>5670.78224486798},
43
+
44
+ { :index=>{:_routing=>506,:_index=>"optimizer",:_type=>"earnings",:_id=>506}},
45
+ { :total_conversions=>237,:banked_clicks=>232,:total_earnings=>550.6212071428588277,:pending_conversions=>9,:paid_net_earnings=>388.021207142857,:banked_conversions=>225,:pending_earnings=>150.91,:optimizer_id=>506,:total_impressions=>348319,:banked_earnings=>12.92,:bounce_count=>905,:time_on_page=>0,:total_clicks=>4854,:entrances=>1614,:pending_clicks=>1034,:paid_earnings=>537.501207142858},
46
+
47
+ {:index=>{:_routing=>345,:_index=>"optimizer",:_type=>"earnings",:_id=>345}},
48
+ {:total_conversions=>0,:banked_clicks=>0,:total_earnings=>0,:pending_conversions=>0,:paid_net_earnings=>0,:banked_conversions=>0,:pending_earnings=>0,:optimizer_id=>345,:total_impressions=>0,:banked_earnings=>0,:bounce_count=>0,:time_on_page=>0,:total_clicks=>0,:entrances=>0,:pending_clicks=>0,:paid_earnings=>0}
49
+ ]
50
+ end
51
+ let(:messages) { inputs.map {|i| MultiJson.encode(i) } * 3 }
52
+
53
+
54
+
55
+ #
56
+ # Examples
57
+ #
58
+
59
+ it "DOES NOT result in frames being delivered out of order (no UNEXPECTED_FRAME connection exceptions)" do
60
+ received_messages = []
61
+ queue = @channel.queue("amqpgem.tests.concurrent_publishing", :auto_delete => true)
62
+ exchange = @channel.default_exchange
63
+ exchange.on_return do |method, header, body|
64
+ raise "Message was returned: #{method.reply_text}"
65
+ end
66
+
67
+ queue.subscribe do |metadata, payload|
68
+ received_messages << payload
69
+ end
70
+
71
+ EventMachine.add_timer(2.0) do
72
+ # ZOMG THREADS!
73
+ 20.times do
74
+ Thread.new do
75
+ messages.each do |message|
76
+ exchange.publish(message, :routing_key => queue.name, :immediate => true, :mandatory => true)
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+
83
+ # let it run for several seconds because you know, concurrency issues do not always manifest themselves
84
+ # immediately. MK.
85
+ done(14.0) {
86
+ # we don't care about the exact number of messages sent or received, just the fact that there are
87
+ # no UNEXPECTED_FRAME connection-level exceptions. MK.
88
+ }
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Messages with empty bodies" do
6
+
7
+ #
8
+ # Environment
9
+ #
10
+
11
+ include EventedSpec::AMQPSpec
12
+ default_options AMQP_OPTS
13
+ default_timeout 5
14
+
15
+ amqp_before do
16
+ @channel = AMQP::Channel.new
17
+ @channel.on_error do |ch, close|
18
+ raise "Channel-level error!: #{close.inspect}"
19
+ end
20
+
21
+ @queue = @channel.queue("", :auto_delete => true)
22
+ @exchange = @channel.direct("amqpgem.tests.integration.direct.exchange", :auto_delete => true)
23
+
24
+ @queue.bind(@exchange, :routing_key => "builds.all")
25
+ end
26
+
27
+
28
+
29
+ it "can be mixed with any other messages" do
30
+ mailbox1 = Array.new
31
+ mailbox2 = Array.new
32
+
33
+ consumer1 = AMQP::Consumer.new(@channel, @queue).consume
34
+ consumer2 = AMQP::Consumer.new(@channel, @queue).consume
35
+
36
+
37
+ consumer1.on_delivery do |metadata, payload|
38
+ mailbox1 << payload
39
+ end
40
+ consumer2.on_delivery do |metadata, payload|
41
+ mailbox2 << payload
42
+ end
43
+
44
+
45
+ EventMachine.add_timer(0.5) do
46
+ 12.times { @exchange.publish("", :routing_key => "builds.all") }
47
+ 12.times { @exchange.publish(".", :routing_key => "all.builds") }
48
+ 12.times { @exchange.publish("", :routing_key => "all.builds") }
49
+ end
50
+
51
+ done(1.5) {
52
+ mailbox1.size.should == 6
53
+ mailbox2.size.should == 6
54
+ }
55
+ end
56
+ end
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: utf-8
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe "Immediate disconnection" do
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: utf-8
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe "Exclusive server-named queue" do
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: utf-8
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe "Store-and-forward routing" do
@@ -64,7 +65,7 @@ describe "Store-and-forward routing" do
64
65
  end
65
66
 
66
67
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
67
- done(4.0) {
68
+ done(6.0) {
68
69
  number_of_received_messages.should == expected_number_of_messages
69
70
  @queue.unsubscribe
70
71
  }
@@ -84,7 +85,7 @@ describe "Store-and-forward routing" do
84
85
  end
85
86
 
86
87
  # 6 seconds are for Rubinius, it is surprisingly slow on this workload
87
- done(3.0) {
88
+ done(6.0) {
88
89
  number_of_received_messages.should == expected_number_of_messages
89
90
  @queue.unsubscribe
90
91
  }
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: utf-8
2
+
2
3
  require "spec_helper"
3
4
  describe "Topic-based subscription" do
4
5
 
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+
5
+ describe "Messages published before AMQP transaction commits" do
6
+
7
+ #
8
+ # Environment
9
+ #
10
+
11
+ include EventedSpec::AMQPSpec
12
+ default_timeout 1.5
13
+
14
+ amqp_before do
15
+ @producer_channel = AMQP::Channel.new
16
+ @consumer_channel = AMQP::Channel.new
17
+ end
18
+
19
+ # ...
20
+
21
+
22
+ #
23
+ # Examples
24
+ #
25
+
26
+ it "are not accessible to AMQP consumers" do
27
+ exchange = @producer_channel.fanout("amq.fanout")
28
+ queue = @consumer_channel.queue("", :exclusive => true)
29
+
30
+ queue.bind(exchange).subscribe do |metadata, payload|
31
+ fail "Consumer received a message before transaction committed"
32
+ end
33
+
34
+ @producer_channel.tx_select
35
+ EventMachine.add_timer(0.5) do
36
+ 50.times { exchange.publish("before tx.commit") }
37
+ # @producer_channel.tx_commit
38
+ end
39
+
40
+ done(1.2)
41
+ end # it
42
+ end # describe
43
+
44
+
45
+
46
+
47
+ describe "AMQP transaction commit" do
48
+
49
+ #
50
+ # Environment
51
+ #
52
+
53
+ include EventedSpec::AMQPSpec
54
+ default_timeout 1.5
55
+
56
+ amqp_before do
57
+ @producer_channel = AMQP::Channel.new
58
+ @consumer_channel = AMQP::Channel.new
59
+ end
60
+
61
+ # ...
62
+
63
+
64
+ #
65
+ # Examples
66
+ #
67
+
68
+ it "causes messages published since the last tx.select to be delivered to AMQP consumers" do
69
+ exchange = @producer_channel.fanout("amq.fanout")
70
+ queue = @consumer_channel.queue("", :exclusive => true)
71
+
72
+ queue.bind(exchange).subscribe { |metadata, payload| done }
73
+
74
+ @producer_channel.tx_select
75
+ EventMachine.add_timer(0.5) do
76
+ 50.times { exchange.publish("before tx.commit") }
77
+ @producer_channel.tx_commit
78
+ end
79
+
80
+ done(1.2)
81
+ end # it
82
+ end # describe
83
+
84
+
85
+
86
+
87
+ describe "AMQP transaction commit attempt on a non-transactional channel" do
88
+
89
+ #
90
+ # Environment
91
+ #
92
+
93
+ include EventedSpec::AMQPSpec
94
+ default_timeout 1.5
95
+
96
+ amqp_before do
97
+ @producer_channel = AMQP::Channel.new
98
+ @consumer_channel = AMQP::Channel.new
99
+ end
100
+
101
+ # ...
102
+
103
+
104
+ #
105
+ # Examples
106
+ #
107
+
108
+ it "causes channel-level exception" do
109
+ exchange = @producer_channel.fanout("amq.fanout")
110
+ queue = @consumer_channel.queue("", :exclusive => true)
111
+
112
+ queue.bind(exchange).subscribe do |metadata, payload|
113
+ fail "Consumer received a message before transaction committed"
114
+ end
115
+
116
+ @producer_channel.on_error do |ch, channel_close|
117
+ puts "#{channel_close.reply_text}"
118
+ done
119
+ end
120
+ EventMachine.add_timer(0.5) { @producer_channel.tx_commit }
121
+
122
+ done(1.2)
123
+ end # it
124
+ end # describe
@@ -0,0 +1,167 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+
5
+ describe "AMQP transaction rollback" do
6
+
7
+ #
8
+ # Environment
9
+ #
10
+
11
+ include EventedSpec::AMQPSpec
12
+ default_timeout 3.5
13
+
14
+ amqp_before do
15
+ @producer_channel = AMQP::Channel.new
16
+ @consumer_channel = AMQP::Channel.new
17
+ end
18
+
19
+ # ...
20
+
21
+
22
+ #
23
+ # Examples
24
+ #
25
+
26
+ it "voids messages published since the last tx.select" do
27
+ exchange = @producer_channel.fanout("amq.fanout")
28
+ queue = @consumer_channel.queue("", :exclusive => true)
29
+
30
+ queue.bind(exchange).subscribe do |metadata, payload|
31
+ fail "Consumer received a message before transaction committed"
32
+ end
33
+
34
+ @producer_channel.tx_select
35
+ EventMachine.add_timer(0.5) do
36
+ 50.times { exchange.publish("before tx.commit") }
37
+ @producer_channel.tx_rollback
38
+ end
39
+
40
+ done(2.5)
41
+ end # it
42
+ end # describe
43
+
44
+
45
+
46
+
47
+ describe "AMQP connection closure that follows tx.select" do
48
+
49
+ #
50
+ # Environment
51
+ #
52
+
53
+ include EventedSpec::AMQPSpec
54
+ default_timeout 3.5
55
+
56
+ amqp_before do
57
+ @producer_channel = AMQP::Channel.new
58
+ @consumer_channel = AMQP::Channel.new
59
+ end
60
+
61
+ # ...
62
+
63
+
64
+ #
65
+ # Examples
66
+ #
67
+
68
+ it "voids messages published since the last tx.select" do
69
+ exchange = @producer_channel.fanout("amq.fanout")
70
+ queue = @consumer_channel.queue("", :exclusive => true)
71
+
72
+ queue.bind(exchange).subscribe do |metadata, payload|
73
+ fail "Consumer received a message before transaction committed"
74
+ end
75
+
76
+ @producer_channel.tx_select
77
+ EventMachine.add_timer(0.5) do
78
+ 3.times { exchange.publish("before tx.commit") }
79
+ @producer_channel.connection.close
80
+ end
81
+
82
+ done(2.5)
83
+ end # it
84
+ end # describe
85
+
86
+
87
+
88
+
89
+ describe "AMQP channel closure that follows tx.select" do
90
+
91
+ #
92
+ # Environment
93
+ #
94
+
95
+ include EventedSpec::AMQPSpec
96
+ default_timeout 3.5
97
+
98
+ amqp_before do
99
+ @producer_channel = AMQP::Channel.new
100
+ @consumer_channel = AMQP::Channel.new
101
+ end
102
+
103
+ # ...
104
+
105
+
106
+ #
107
+ # Examples
108
+ #
109
+
110
+ it "voids messages published since the last tx.select" do
111
+ exchange = @producer_channel.fanout("amq.fanout")
112
+ queue = @consumer_channel.queue("", :exclusive => true)
113
+
114
+ queue.bind(exchange).subscribe do |metadata, payload|
115
+ fail "Consumer received a message before transaction committed"
116
+ end
117
+
118
+ @producer_channel.tx_select
119
+ EventMachine.add_timer(0.5) do
120
+ 3.times { exchange.publish("before tx.commit") }
121
+ @producer_channel.close
122
+ end
123
+
124
+ done(2.5)
125
+ end # it
126
+ end # describe
127
+
128
+
129
+
130
+ describe "AMQP transaction rollback attempt on a non-transactional channel" do
131
+
132
+ #
133
+ # Environment
134
+ #
135
+
136
+ include EventedSpec::AMQPSpec
137
+ default_timeout 3.5
138
+
139
+ amqp_before do
140
+ @producer_channel = AMQP::Channel.new
141
+ @consumer_channel = AMQP::Channel.new
142
+ end
143
+
144
+ # ...
145
+
146
+
147
+ #
148
+ # Examples
149
+ #
150
+
151
+ it "causes channel-level exception" do
152
+ exchange = @producer_channel.fanout("amq.fanout")
153
+ queue = @consumer_channel.queue("", :exclusive => true)
154
+
155
+ queue.bind(exchange).subscribe do |metadata, payload|
156
+ fail "Consumer received a message before transaction committed"
157
+ end
158
+
159
+ @producer_channel.on_error do |ch, channel_close|
160
+ puts "#{channel_close.reply_text}"
161
+ done
162
+ end
163
+ EventMachine.add_timer(0.5) { @producer_channel.tx_rollback }
164
+
165
+ done(2.5)
166
+ end # it
167
+ end # describe