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
@@ -1,11 +1,13 @@
1
1
  # @title Ruby AMQP gem: Using TLS
2
2
 
3
- h1. TBD
3
+ h1. Using TLS with Ruby amqp gem
4
4
 
5
5
 
6
6
  h2. About this guide
7
7
 
8
- TBD
8
+ This guide covers connection to AMQP brokers using TLS (also known as SSL) and related issues. This guide
9
+ does not explain basic TLS concepts. For that, refer to resources like "Introduction to SSL":https://developer.mozilla.org/en/Introduction_to_SSL
10
+ or "Wikipedia page on TLS":http://en.wikipedia.org/wiki/Transport_Layer_Security.
9
11
 
10
12
 
11
13
  h2. Covered versions
@@ -13,16 +15,74 @@ h2. Covered versions
13
15
  This guide covers "Ruby amqp gem":http://github.com/ruby-amqp/amqp v0.8.0 and later.
14
16
 
15
17
 
18
+ h2. Broker version requirements
16
19
 
17
- h2. TBD
20
+ h3. RabbitMQ
18
21
 
19
- TBD
22
+ RabbitMQ supports TLS since version 1.7.0. Minimum requirements are
23
+
24
+ * Erlang R13B
25
+ * Erlang SSL application 3.10
26
+
27
+ The recommended distribution is R14B (SSL 4.0.1) or later. This should be considered the minimum configuration for Java
28
+ and Erlang clients due to an incorrect RC4 implementation in earlier versions of Erlang.
29
+
30
+ Learn more at "rabbitmq.com TLS page":http://www.rabbitmq.com/ssl.html.
31
+
32
+
33
+
34
+ h2. Pre-requisites
35
+
36
+ AMQP brokers typically need to be configured to use TLS. Just like Web servers, TLS connections are usually accepted
37
+ on a separate port (5671). "rabbitmq.com TLS page":http://www.rabbitmq.com/ssl.html describes how to configure RabbitMQ
38
+ to use TLS, how to generate certificates for development and so on.
39
+
40
+
41
+
42
+ h2. Connecting to AMQP broker using TLS
43
+
44
+ To instruct Ruby amqp gem to use TLS for connection, pass :ssl option that specifies certificate chain file path
45
+ as well as private key file path:
46
+
47
+ <pre>
48
+ <code>
49
+ AMQP.start(:port => 5671,
50
+ :ssl => {
51
+ :cert_chain_file => certificate_chain_file_path,
52
+ :private_key_file => client_private_key_file_path
53
+ }) do |connection|
54
+ puts "Connected, authenticated. TLS seems to work."
55
+
56
+ connection.disconnect { puts "Now closing the connection…"; EventMachine.stop }
57
+ end
58
+ </code>
59
+ </pre>
60
+
61
+ Note that TLS connection may take a bit of time to establish (up to several seconds in some cases). To verify that
62
+ broker connection actually uses TLS, refer to RabbitMQ log file:
63
+
64
+ <pre>
65
+ =INFO REPORT==== 28-Jun-2011::08:41:24 ===
66
+ accepted TCP connection on 0.0.0.0:5671 from 127.0.0.1:53444
67
+
68
+ =INFO REPORT==== 28-Jun-2011::08:41:24 ===
69
+ starting TCP connection <0.9904.0> from 127.0.0.1:53444
70
+
71
+ =INFO REPORT==== 28-Jun-2011::08:41:24 ===
72
+ upgraded TCP connection <0.9904.0> to SSL
73
+ </pre>
74
+
75
+
76
+
77
+ h2. Example code
78
+
79
+ TLS example (as well as sample certificates you can use to get started with) can be found in the "amqp gem git repository":https://github.com/ruby-amqp/amqp/tree/master/examples
20
80
 
21
81
 
22
82
 
23
83
  h2. Tell us what you think!
24
84
 
25
- Please take a moment and tell us what you think about this guide on "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp:
85
+ Please take a moment and tell us what you think about this guide "on Twitter":http://twitter.com/rubyamqp or "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp:
26
86
  what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is
27
87
  key to making documentation better.
28
88
 
@@ -2,32 +2,112 @@
2
2
 
3
3
  h1. Ruby AMQP gem documentation guides
4
4
 
5
- h2. Guide list
5
+ h2. Which versions of the amqp gem do the guides cover?
6
6
 
7
- * {file:docs/GettingStarted.textile Getting started}
8
- * {file:docs/ConnectingToTheBroker.textile Connecting to the broker}
9
- * {file:docs/Queues.textile Working with queues}
10
- * {file:docs/Exchanges.textile Working with exchanges}
7
+ These guides cover v0.8.0.RC13 and later of the "Ruby amqp gem":http://github.com/ruby-amqp/amqp.
8
+
9
+
10
+ h2. Documentation structure and how to read these guides
11
+
12
+ We recommend that you read the documentation guides in the order that they are listed. The *Getting Started* guide is written as a tutorial that
13
+ describes several typical applications and their problem scope, then provides full code examples and finally breaks them down
14
+ into smaller pieces that are explained in detail.
15
+
16
+ Once you are finished with the tutorial, reading the other guides in sequence will gradually explain all of the AMQP 0.9.1 features that are relevant to
17
+ application developers, including application design concerns and common practices. At present, some guides are yet to be written
18
+ but *most of the content is concentrated in just 3-4 guides* that are about 80% finished and provide plenty of examples.
19
+
20
+ Here is a summary of guides and their content:
21
+
22
+ <dl>
23
+ <dt>{file:docs/GettingStarted.textile Getting Started}</dt>
24
+ <dd>
25
+ Walks you through gem installation and 3 applications that demonstrate what AMQP has to offer. Explains how amqp gem should
26
+ be integrated into rich object-oriented Ruby programs.
27
+ </dd>
28
+
29
+
30
+ <dt>{file:docs/AMQP091ModelExplained.textile AMQP 0.9.1 Model Explained}</dt>
31
+ <dd>
32
+ Explains the AMQP 0.9.1 model, focusing on what purpose individual features have. Reading
33
+ other documentation guides will be easier when you are armed with this knowledge: a lot of the AMQP & RabbitMQ power
34
+ comes from the AMQP model.
35
+ </dd>
36
+
37
+ <dt>{file:docs/ConnectingToTheBroker.textile Connecting to the Broker}</dt>
38
+ <dd>
39
+ Connecting to AMQP broker. How to integrate with standalone applications as well as Ruby on Rails, Merb, Sinatra or Rack apps.
40
+ What difference application server (Unicorn, Passenger, Thin, etc) makes. How to handle authentication failures and network
41
+ connectivity issues. Closing AMQP connection gracefully.
42
+ </dd>
43
+
44
+ <dt>{file:docs/Queues.textile Working With Queues}</dt>
45
+ <dd>
46
+ What AMQP queues are. How to declare AMQP queues. When and how to use server-named and explicitly named queues. How to subscribe
47
+ for "push" message delivery. What message acknowledgements are. How to access AMQP message metadata. How to fetch ("pull") messages
48
+ from queues on demand. How to bind and unbind a queue to an exchange. How to delete a queue.
49
+ </dd>
50
+
51
+ <dt>{file:docs/Exchanges.textile Working With Exchanges}</dt>
52
+ <dd>
53
+ What AMQP exchanges are. Concept of binding. How to declare AMQP exchanges. How different exchange types route messages and common
54
+ use cases. How to publish messages, especially how to do it reliably. What AMQP transactions are. What Publisher Confirms are.
55
+ How to delete an exchange.
56
+ </dd>
57
+
58
+ <dt>{file:docs/PatternsAndUseCases.textile Patterns and Use Cases}</dt>
59
+ <dd>Typical use cases, patterns and routing topologies.</dd>
60
+
61
+ <dt>{file:docs/Durability.textile Durability and Message Persistence}</dt>
62
+ <dd>Exchange durability. Queue durability. Message persistence. Performance implications.</dd>
63
+
64
+ <dt>{file:docs/ErrorHandling.textile Error Handling and Recovery}</dt>
65
+ <dd>
66
+ Network failures. Connection-level exceptions. Channel-level exceptions. Why error handling is easy but
67
+ recovery is hard. How to survive typical problems. What other tools can help (e.g. HAProxy).
68
+ </dd>
69
+
70
+ <dt>{file:docs/RabbitMQVersions.textile RabbitMQ versions}</dt>
71
+ <dd>
72
+ RabbitMQ versions that amqp gem supports. Popular Linux distributions and RabbitMQ versions they ship. How to obtain up-to-date official
73
+ packages of RabbitMQ.
74
+ </dd>
75
+
76
+ <dt>{file:docs/ConnectionEncryptionWithTLS.textile Using TLS (SSL)}</dt>
77
+ <dd>All things related to TLS-encrypted connections.</dd>
78
+ </dl>
79
+
80
+
81
+ When more than one guide describes the same concept, we make sure to use cross-references, however, only one guide discusses the concept in detail.
82
+
83
+
84
+ h2. Full guide list
85
+
86
+ * {file:docs/GettingStarted.textile Getting Started}
87
+ * {file:docs/AMQP091ModelExplained.textile AMQP 0.9.1 Model Explained}
88
+ * {file:docs/ConnectingToTheBroker.textile Connecting to the Broker}
89
+ * {file:docs/Queues.textile Working With Queues}
90
+ * {file:docs/Exchanges.textile Working With Exchanges}
11
91
  * {file:docs/Bindings.textile Bindings}
12
- * {file:docs/Routing.textile Routing}
13
- * {file:docs/Durability.textile Durability and message persistence}
14
- * {file:docs/ErrorHandling.textile Error handling}
92
+ * {file:docs/PatternsAndUseCases.textile Patterns and Use Cases}
93
+ * {file:docs/Durability.textile Durability and Message Persistence}
94
+ * {file:docs/ErrorHandling.textile Error Handling and Recovery}
15
95
  * {file:docs/08Migration.textile Upgrading from version 0.6.x/0.7.x to 0.8.x and above}
16
96
  * {file:docs/Troubleshooting.textile Troubleshooting and debugging AMQP applications}
17
97
  * {file:docs/Clustering.textile Clustering}
18
98
  * {file:docs/RabbitMQVersions.textile RabbitMQ versions}
19
99
  * {file:docs/ConnectionEncryptionWithTLS.textile Using TLS (SSL)}
20
- * {file:docs/VendorSpecificExtensions.textile Vendor-specific extensions to AMQP 0.9.1 spec}
100
+ * {file:docs/VendorSpecificExtensions.textile Vendor-specific Extensions to AMQP 0.9.1 spec}
21
101
  * {file:docs/RunningTests.textile Running amqp gem test suite}
22
102
 
23
103
 
24
104
  h2. Tell us what you think!
25
105
 
26
- Please take a moment and tell us what you think about this guide on "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp:
27
- what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is
28
- key to making documentation better.
106
+ Please take a moment to tell us what you think about this guide "on Twitter":http://twitter.com/rubyamqp or the "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp.
107
+ Let us know what was unclear or what has not been covered. Maybe you do not like the guide style or grammar or discover spelling mistakes. Reader feedback is
108
+ key to making the documentation better.
29
109
 
30
- If mailing list communication is not an option for you for some reason, you can "contact guides author directly":mailto:michael@novemberain.com?subject=amqp%20gem%20documentation
110
+ If, for some reason, you cannot use the communication channels mentioned above, you can "contact the author of the guides directly":mailto:michael@novemberain.com?subject=amqp%20gem%20documentation
31
111
 
32
112
 
33
113
  <div id="disqus_thread"></div>
@@ -98,7 +98,7 @@ See {file:docs/Clustering.textile Clustering guide} for in-depth discussion of t
98
98
 
99
99
  h2. Tell us what you think!
100
100
 
101
- Please take a moment and tell us what you think about this guide on "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp:
101
+ Please take a moment and tell us what you think about this guide "on Twitter":http://twitter.com/rubyamqp or "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp:
102
102
  what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is
103
103
  key to making documentation better.
104
104
 
@@ -9,17 +9,23 @@ multiple kinds of failures: protocol exceptions, network failures, broker failur
9
9
  Correct error handling and recovery is not easy. This guide explains how amqp gem helps you in dealing with
10
10
  issues like
11
11
 
12
- * Broker connection failures
12
+ * Initial broker connection failures
13
13
  * Network connection interruption
14
- * TLS (SSL) related issues
15
14
  * AMQP connection-level exceptions
16
15
  * AMQP channel-level exceptions
17
16
  * Broker failure
17
+ * TLS (SSL) related issues
18
+
19
+ as well as
20
+
21
+ * How to recover after a network failure
22
+ * What is automatic recovery mode, when you should and should not use it
23
+
18
24
 
19
25
 
20
26
  h2. Covered versions
21
27
 
22
- This guide covers "Ruby amqp gem":http://github.com/ruby-amqp/amqp v0.8.0 and later.
28
+ This guide covers "Ruby amqp gem":http://github.com/ruby-amqp/amqp v0.8.0.RC14 and later.
23
29
 
24
30
 
25
31
  h2. Code examples
@@ -28,7 +34,7 @@ There are several {https://github.com/ruby-amqp/amqp/tree/master/examples/error_
28
34
  free to contribute new examples.
29
35
 
30
36
 
31
- h3. Broker connection failures
37
+ h3. Initial broker connection failures
32
38
 
33
39
  When applications connect to the broker, they need to handle connection failures. Networks are not 100% reliable, even with modern system configuration tools
34
40
  like Chef or Puppet misconfigurations happen and broker might be down, too. Error detection should happen as early as possible. There are two ways of detecting
@@ -36,24 +42,6 @@ TCP connection failure, the first one is to catch an exception:
36
42
 
37
43
  <pre>
38
44
  <code>
39
- #!/usr/bin/env ruby
40
- # encoding: utf-8
41
-
42
- require "rubygems"
43
- require "amqp"
44
-
45
-
46
- puts "=> TCP connection failure handling with a rescue statement"
47
- puts
48
-
49
- connection_settings = {
50
- :port => 9689,
51
- :vhost => "/amq_client_testbed",
52
- :user => "amq_client_gem",
53
- :password => "amq_client_gem_password",
54
- :timeout => 0.3
55
- }
56
-
57
45
  begin
58
46
  AMQP.start(connection_settings) do |connection, open_ok|
59
47
  raise "This should not be reachable"
@@ -64,6 +52,9 @@ end
64
52
  </code>
65
53
  </pre>
66
54
 
55
+ Full example:
56
+ <script src="https://gist.github.com/1016238.js"> </script>
57
+
67
58
  {AMQP.connect} (and {AMQP.start}) will raise {AMQP::TCPConnectionFailed} if connection fails. Code that catches it can write to log
68
59
  about the issue or use retry to execute begin block one more time. Because initial connection failures are due to misconfiguration or network outage, reconnection
69
60
  to the same endpoint (hostname, port, vhost combination) will result in the same issue over and over. TBD: failover, connection to the cluster.
@@ -72,16 +63,7 @@ Alternative way of handling connection failure is with an errback (a callback fo
72
63
 
73
64
  <pre>
74
65
  <code>
75
- #!/usr/bin/env ruby
76
- # encoding: utf-8
77
-
78
- require "rubygems"
79
- require "amqp"
80
-
81
- puts "=> TCP connection failure handling with a callback"
82
- puts
83
-
84
- handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop }
66
+ handler = Proc.new { |settings| puts "Failed to connect, as expected"; EventMachine.stop }
85
67
  connection_settings = {
86
68
  :port => 9689,
87
69
  :vhost => "/amq_client_testbed",
@@ -90,14 +72,12 @@ connection_settings = {
90
72
  :timeout => 0.3,
91
73
  :on_tcp_connection_failure => handler
92
74
  }
93
-
94
-
95
- AMQP.start(connection_settings) do |connection, open_ok|
96
- raise "This should not be reachable"
97
- end
98
75
  </code>
99
76
  </pre>
100
77
 
78
+ Full example:
79
+ <script src="https://gist.github.com/1016235.js"> </script>
80
+
101
81
  :on_tcp_connection_failure option accepts any object that responds to #call.
102
82
 
103
83
  If you connect to the broker from a code in a class (as opposed to top-level scope in a script), Object#method can be used to pass object method as a handler
@@ -111,126 +91,510 @@ h3. Authentication failures
111
91
  Another reason why connection may fail is authentication failure. Handling authentication failure is very similar to handling initial TCP
112
92
  connection failure:
113
93
 
94
+ <script src="https://gist.github.com/1016233.js"> </script>
95
+
96
+
97
+ h4. Default handler
98
+
99
+ default handler raises {AMQP::PossibleAuthenticationFailureError}:
100
+
101
+ <script src="https://gist.github.com/1016234.js"> </script>
102
+
103
+ In case you wonder why callback name has "possible" in it: {http://bit.ly/mTr1YN AMQP 0.9.1 spec} requires broker implementations to
104
+ simply close TCP connection without sending any more data when an exception (such as authentication failure) occurs before AMQP connection
105
+ is open. In practice, however, when broker closes TCP connection between successful TCP connection and before AMQP connection is open,
106
+ it means that authentication has failed.
107
+
108
+
109
+
110
+ h2. Handling network connection interruptions
111
+
112
+ Network connectivity issues are sad fact of life in modern software systems. Event small products and projects these days consist of multiple
113
+ applications, often running on more than one machine. Ruby amqp gem detects TCP connection failures and lets you handle them by
114
+ defining a callback using {AMQP::Session#on_tcp_connection_loss}. That callback will be run when TCP connection fails, and will be passed
115
+ two parameters: connection object and settings of the last successful connection.
116
+
114
117
  <pre>
115
118
  <code>
116
- #!/usr/bin/env ruby
117
- # encoding: utf-8
119
+ connection.on_tcp_connection_loss do |connection, settings|
120
+ # reconnect in 10 seconds, without enforcement
121
+ connection.reconnect(false, 10)
122
+ end
123
+ </code>
124
+ </pre>
118
125
 
119
- require "rubygems"
120
- require "amqp"
126
+ Sometimes it is necessary for other entities in an application to react to network failures. amqp gem 0.8.0 and later provides a number event
127
+ handlers to make this task easier for developers. This set of features is know as the "shutdown protocol" (the word "protocol" here means
128
+ "API interface" or "behavior", not network protocol).
121
129
 
122
- puts "=> Authentication failure handling with a callback"
123
- puts
130
+ {AMQP::Session}, {AMQP::Channel}, {AMQP::Exchange}, {AMQP::Queue} and {AMQP::Consumer all implement shutdown protocol and thus error
131
+ handling API is consistent for all classes, with {AMQP::Session} and #{AMQP::Channel} having a few methods other entities do not have.
124
132
 
125
- handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop }
126
- connection_settings = {
127
- :port => 5672,
128
- :vhost => "/amq_client_testbed",
129
- :user => "amq_client_gem",
130
- :password => "amq_client_gem_password_that_is_incorrect #{Time.now.to_i}",
131
- :timeout => 0.3,
132
- :on_tcp_connection_failure => handler,
133
- :on_possible_authentication_failure => Proc.new { |settings|
134
- puts "Authentication failed, as expected, settings are: #{settings.inspect}"
133
+ The Shutdown protocol revolves around two events:
135
134
 
136
- EM.stop
137
- }
138
- }
135
+ * Network connection fails
136
+ * Broker closes AMQP connection (or channel)
137
+
138
+ In this section, we concentrate only on the former. When network connection fails, the underlying networking library detects it and
139
+ runs a piece of code on {AMQP::Session} to handle it. That, in turn, propagates this event to channels, channels propagate it to
140
+ exchanges and queues, queues propagate it to their consumers (if any). Each of these entities in the object graph can react
141
+ to network interruption by executing application-defined callbacks.
142
+
143
+ h3. Shutdown Protocol methods on AMQP::Session
139
144
 
140
- AMQP.start(connection_settings) do |connection, open_ok|
141
- raise "This should not be reachable"
145
+ * {AMQP::Session#on_tcp_connection_loss}
146
+ * {AMQP::Session#on_connection_interruption}
147
+
148
+ The difference between these methods is that {AMQP::Session#on_tcp_connection_loss} is used to define a callback that will
149
+ be executed *once* when TCP connection fails. It is possible that reconnection attempts will not succeed immediately, so
150
+ there will be subsequent failures. To react to those, {AMQP::Session#on_connection_interruption} method is used.
151
+
152
+ First argument that both of these methods yield to the handler your application defines is the connection itself. This is
153
+ done to make sure you can register Ruby objects as handlers, and they do not have to keep any state around (for example,
154
+ connection instances):
155
+
156
+ <pre>
157
+ <code>
158
+ connection.on_connection_interruption do |conn|
159
+ puts "Connection detected connection interruption"
142
160
  end
161
+
162
+ # or
163
+
164
+ class ConnectionInterruptionHandler
165
+
166
+ #
167
+ # API
168
+ #
169
+
170
+ def handle(connection)
171
+ # handling logic
172
+ end
173
+
174
+ end
175
+
176
+ handler = ConnectionInterruptionHandler.new
177
+ connection.on_connection_interruption(&handler.method(:handle))
143
178
  </code>
144
179
  </pre>
145
180
 
146
- default handler raises {AMQP::PossibleAuthenticationFailureError}:
181
+ Note that {AMQP::Session#on_connection_interruption} callback is called *before* this event is propagated to channels, queues and so on.
182
+
183
+ Different applications handle connection failures differently. It is very common to use {AMQP::Session#reconnect} method
184
+ to schedule a reconnection to the same host, or use {AMQP::Session#reconnect_to} to connect to a different one.
185
+
186
+ For some applications it is OK to simply exit and wait to be restarted at a later point in time, for example, by a process
187
+ monitoring system like Nagios or Monit.
188
+
189
+
190
+ h3. Shutdown Protocol methods on AMQP::Channel
191
+
192
+ {AMQP::Channel} provides only one method: {AMQP::Channel#on_connection_interruption}, that registers a callback similar to
193
+ the one seen in the previous section:
147
194
 
148
195
  <pre>
149
196
  <code>
150
- #!/usr/bin/env ruby
151
- # encoding: utf-8
197
+ channel.on_connection_interruption do |ch|
198
+ puts "Channel #{ch.id} detected connection interruption"
199
+ end
200
+ </code>
201
+ </pre>
152
202
 
153
- require "rubygems"
154
- require "amqp"
203
+ Note that {AMQP::Channel#on_connection_interruption} callback is called *after* this event is propagated to exchanges, queues and so on.
204
+ Right after that channel state is reset, except for error handling/recovery-related callbacks.
155
205
 
156
- puts "=> Authentication failure handling with a rescue block"
157
- puts
206
+ <span class="note">
207
+ Many applications do not need per-channel network failure handling.
208
+ </span>
158
209
 
159
- handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop }
160
- connection_settings = {
161
- :port => 5672,
162
- :vhost => "/amq_client_testbed",
163
- :user => "amq_client_gem",
164
- :password => "amq_client_gem_password_that_is_incorrect #{Time.now.to_i}",
165
- :timeout => 0.3,
166
- :on_tcp_connection_failure => handler
167
- }
168
210
 
211
+ h3. Shutdown Protocol methods on AMQP::Exchange
169
212
 
170
- begin
171
- AMQP.start(connection_settings) do |connection, open_ok|
172
- raise "This should not be reachable"
173
- end
174
- rescue AMQP::PossibleAuthenticationFailureError => afe
175
- puts "Authentication failed, as expected, caught #{afe.inspect}"
176
- EventMachine.stop if EventMachine.reactor_running?
213
+ {AMQP::Exchange} provides only one method: {AMQP::Exchange#on_connection_interruption}, that registers a callback similar to
214
+ the one seen in the previous section:
215
+
216
+ <pre>
217
+ <code>
218
+ exchange.on_connection_interruption do |ex|
219
+ puts "Exchange #{ex.name} detected connection interruption"
177
220
  end
178
221
  </code>
179
222
  </pre>
180
223
 
181
- In case you wonder why callback name has "possible" in it: {http://bit.ly/mTr1YN AMQP 0.9.1 spec} requires broker implementations to
182
- simply close TCP connection without sending any more data when an exception (such as authentication failure) occurs before AMQP connection
183
- is open. In practice, however, when broker closes TCP connection between successful TCP connection and before AMQP connection is open,
184
- it means that authentication has failed.
224
+ <span class="note">
225
+ Many applications do not need per-exchange network failure handling.
226
+ </span>
185
227
 
186
228
 
229
+ h3. Shutdown Protocol methods on AMQP::Queue
187
230
 
188
- h2. Network connection interruption
231
+ {AMQP::Queue} provides only one method: {AMQP::Queue#on_connection_interruption}, that registers a callback similar to
232
+ the one seen in the previous section:
189
233
 
190
- TBD
234
+ <pre>
235
+ <code>
236
+ queue.on_connection_interruption do |q|
237
+ puts "Queue #{q.name} detected connection interruption"
238
+ end
239
+ </code>
240
+ </pre>
191
241
 
242
+ Note that {AMQP::Queue#on_connection_interruption} callback is called *after* this event is propagated to consumers.
192
243
 
244
+ <span class="note">
245
+ Many applications do not need per-queue network failure handling.
246
+ </span>
193
247
 
194
- h2. TLS (SSL) related issues
195
248
 
196
- TBD
249
+ h3. Shutdown Protocol methods on AMQP::Consumer
250
+
251
+ {AMQP::Consumer} provides only one method: {AMQP::Consumer#on_connection_interruption}, that registers a callback similar to
252
+ the one seen in the previous section:
253
+
254
+ <pre>
255
+ <code>
256
+ consumer.on_connection_interruption do |c|
257
+ puts "Consumer with consumer tag #{c.consumer_tag} detected connection interruption"
258
+ end
259
+ </code>
260
+ </pre>
261
+
262
+ <span class="note">
263
+ Many applications do not need per-consumer network failure handling.
264
+ </span>
265
+
266
+
267
+
268
+ h2. Recovering from network connection failures
269
+
270
+ Detecting network connections is nearly useless if AMQP-based application cannot recover from them. Recovery is the hard part
271
+ in "error handling and recovery". Fortunately, recovery process for many applications follows one simple scheme that amqp
272
+ gem can perform automatically for you.
273
+
274
+ h3. Manual recovery
275
+
276
+ Similarly to the Shutdown Protocol, amqp gem entities implement Recovery Protocol. Recovery Protocol consists of 3 methods
277
+ connections, channels, queues, consumers and exchanges implement:
278
+
279
+ * {AMQP::Session#before_recovery}
280
+ * {AMQP::Session#auto_recover}
281
+ * {AMQP::Session#after_recovery}
282
+
283
+ {AMQP::Session#before_recovery} lets application developers register a callback that will be executed *after TCP connection is
284
+ re-established but before AMQP connection is reopened*. {AMQP::Session#after_recovery} is similar except that the callback is run
285
+ *after AMQP connection is reopened*.
286
+
287
+ {AMQP::Channel}, {AMQP::Queue}, {AMQP::Consumer} and {AMQP::Exchange} methods behavior is identical.
288
+
289
+
290
+ h3. Automatic recovery
291
+
292
+ Many applications use the same recovery strategy, that consists of the following steps:
293
+
294
+ * Re-open channels
295
+ * For each channel, re-declare exchanges
296
+ * For each channel, re-declare queues
297
+ * For each queue, recover all bindings
298
+ * For each queue, recover all consumers
299
+
300
+ amqp gem provides a feature known as "automatic recovery" that is *opt-in* (not opt-out, not used by default) and lets application
301
+ developers get aforementioned recovery strategy by setting one additional attribute on {AMQP::Channel} instance:
302
+
303
+ <pre>
304
+ <code>
305
+ ch = AMQP::Channel.new(connection)
306
+ ch.auto_recovery = true
307
+ </code>
308
+ </pre>
309
+
310
+
311
+ A more verbose way to do the same thing:
312
+ <pre>
313
+ <code>
314
+ ch = AMQP::Channel.new(connection, AMQP::Channel.next_channel_id, :auto_recovery => true)
315
+ </code>
316
+ </pre>
317
+
318
+ Note that if you do not want to pass any options, 2nd argument can be left out as well,
319
+ then it will default to {AMQP::Channel.next_channel_id}.
320
+
321
+
322
+ To find out whether channel uses automatic recovery mode, use {AMQP::Channel#auto_recovering?}.
323
+
324
+ Auto recovery mode can be turned on and off any number of times during channel life cycle, although very small percentage of
325
+ applications really does this. Typically you decide what channels should be using automatic recovery at application design
326
+ stage.
327
+
328
+ Full example (run it, then shut down AMQP broker running on localhost, then bring it back up and use management tools such as `rabbitmqctl`
329
+ to see that queues & bindings & consumer have all recovered):
330
+ <script src="https://gist.github.com/1048076.js"> </script>
331
+
332
+ Server-named queues, when recovered automatically, will get *new server-generated names* to guarantee there are no name collisions.
333
+
334
+ <span note="class">
335
+ When in doubt, try using automatic recovery first. If it is not sufficient for you application, switch to manual
336
+ recovery using events and callbacks introduced in the "Manual recovery" section.
337
+ </span>
338
+
339
+
340
+ h2. Detecting broker failures
341
+
342
+ AMQP applications see broker failure as TCP connection loss. There is no reliable way to know whether there is a network split
343
+ or network peer is down.
344
+
197
345
 
198
346
 
199
347
 
200
348
  h2. AMQP connection-level exceptions
201
349
 
350
+ h3. Handling connection-level exceptions
351
+
352
+ Connection-level exceptions are rare and may indicate a serious issue with client library or in-flight data corruption. They mandate
353
+ that connection cannot be used any more and must be closed. In any case, your application should be prepared to handle this kind of errors.
354
+ To define a handler, use {AMQP::Session#on_error} method that takes a callback and yields two arguments to it when connection-level exception happens:
355
+
356
+ <pre>
357
+ <code>
358
+ connection.on_error do |conn, connection_close|
359
+ puts "Handling a connection-level exception."
360
+ puts
361
+ puts "AMQP class id : #{connection_close.class_id}"
362
+ puts "AMQP method id: #{connection_close.method_id}"
363
+ puts "Status code : #{connection_close.reply_code}"
364
+ puts "Error message : #{connection_close.reply_text}"
365
+ end
366
+ </code>
367
+ </pre>
368
+
369
+ Status codes are similar to those of HTTP. For the full list of error codes and their meaning, consult {http://www.rabbitmq.com/amqp-0-9-1-reference.html#constants AMQP 0.9.1 constants reference}.
370
+
371
+ <span class="note">
372
+ Only one connection-level exception handler can be defined per connection instance (the one added last replaces previously added ones).
373
+ </span>
374
+
375
+ Full example:
376
+ <script src="https://gist.github.com/1015966.js"> </script>
377
+
378
+
379
+
380
+ h2. Handling graceful broker shutdown
381
+
382
+ When AMQP broker is shut down, it properly closes connection first. To do so, it uses *connection.close* AMQP method. AMQP clients then
383
+ need to check if the reply code is equal to 320 (CONNECTION_FORCED) to distinguish graceful shutdown. With RabbitMQ, when broker
384
+ is stopped using
385
+
386
+ <pre>rabbitmqctl stop</pre>
387
+
388
+ reply_text will be set to
389
+
390
+ <pre>CONNECTION_FORCED - broker forced connection closure with reason 'shutdown'</pre>
391
+
392
+ Each application choose how to handle graceful broker shutdowns individually, so *amqp gem's automatic reconnection does not cover graceful broker shutdowns*.
393
+ Applications that want to reconnect when broker is stopped can use {AMQP::Session#periodically_reconnect} like so:
394
+
395
+ <pre>
396
+ <code>
397
+ connection.on_error do |conn, connection_close|
398
+ puts "[connection.close] Reply code = #{connection_close.reply_code}, reply text = #{connection_close.reply_text}"
399
+ if connection_close.reply_code == 320
400
+ puts "[connection.close] Setting up a periodic reconnection timer..."
401
+ # every 30 seconds
402
+ conn.periodically_reconnect(30)
403
+ end
404
+ end
405
+ </code>
406
+ </pre>
407
+
408
+ Once AMQP connection is re-opened, channels in automatic recovery mode will recover just like they do after network outages.
409
+
410
+
411
+ h2. Integrating channel-level exceptions handling with object-oriented Ruby code
412
+
413
+ Error handling can be easily integrated into object-oriented Ruby code (in fact, this is highly encouraged).
414
+ A common technique is to combine {http://rubydoc.info/stdlib/core/1.8.7/Object:method Object#method} and {http://rubydoc.info/stdlib/core/1.8.7/Method:to_proc Method#to_proc}
415
+ and use object methods as error handlers:
416
+
417
+ <pre>
418
+ <code>
419
+ class ConnectionManager
420
+
421
+ #
422
+ # API
423
+ #
424
+
425
+ def connect(*args, &block)
426
+ @connection = AMQP.connect(*args, &block)
427
+
428
+ # combines Object#method and Method#to_proc to use object
429
+ # method as a callback
430
+ @connection.on_error(&method(:on_error))
431
+ end # connect(*args, &block)
432
+
433
+
434
+ def on_error(connection, connection_close)
435
+ puts "Handling a connection-level exception."
436
+ puts
437
+ puts "AMQP class id : #{connection_close.class_id}"
438
+ puts "AMQP method id: #{connection_close.method_id}"
439
+ puts "Status code : #{connection_close.reply_code}"
440
+ puts "Error message : #{connection_close.reply_text}"
441
+ end # on_error(connection, connection_close)
442
+ end
443
+ </code>
444
+ </pre>
445
+
446
+ Full example that uses objects:
447
+ <script src="https://gist.github.com/1016049.js"> </script>
448
+
202
449
  TBD
203
450
 
204
451
 
205
452
 
453
+
206
454
  h2. AMQP channel-level exceptions
207
455
 
208
- TBD
456
+ h3. Hanling channel-level exceptions
209
457
 
458
+ Channel-level exceptions are more common than connection-level ones. They are handled in a similar manner, by defining a callback
459
+ with {AMQP::Channel#on_error} method that takes a callback and yields two arguments to it when channel-level exception happens:
210
460
 
461
+ <pre>
462
+ <code>
463
+ channel.on_error do |ch, channel_close|
464
+ puts "Handling a channel-level exception."
465
+ puts
466
+ puts "AMQP class id : #{channel_close.class_id}"
467
+ puts "AMQP method id: #{channel_close.method_id}"
468
+ puts "Status code : #{channel_close.reply_code}"
469
+ puts "Error message : #{channel_close.reply_text}"
470
+ end
471
+ </code>
472
+ </pre>
211
473
 
212
- h2. Broker failure
474
+ Status codes are similar to those of HTTP. For the full list of error codes and their meaning, consult {http://www.rabbitmq.com/amqp-0-9-1-reference.html#constants AMQP 0.9.1 constants reference}.
213
475
 
214
- TBD
476
+ <span class="note">
477
+ Only one channel-level exception handler can be defined per channel instance (the one added last replaces previously added ones).
478
+ </span>
479
+
480
+ Full example:
481
+ <script src="https://gist.github.com/1016042.js"> </script>
215
482
 
216
483
 
484
+ h3. Integrating channel-level exceptions handling with object-oriented Ruby code
217
485
 
486
+ Error handling can be easily integrated into object-oriented Ruby code (in fact, this is highly encouraged).
487
+ A common technique is to combine {http://rubydoc.info/stdlib/core/1.8.7/Object:method Object#method} and {http://rubydoc.info/stdlib/core/1.8.7/Method:to_proc Method#to_proc}
488
+ and use object methods as error handlers. For example of this, see section on connection-level exceptions above.
218
489
 
219
- h2. Recovery
490
+
491
+ h3. Common channel-level exceptions and what they mean
492
+
493
+ A few channel-level exceptions are common and deserve more attention.
494
+
495
+ h4. 406 Precondition Failed
496
+
497
+ <dl>
498
+ <dt>Description</dt>
499
+ <dd>The client requested a method that was not allowed because some precondition failed.</dd>
500
+
501
+ <dt>What might cause it</dt>
502
+ <dd>
503
+ <ul>
504
+ <li>
505
+ AMQP entity (a queue or exchange) was re-declared with attributes different from original declaration. Maybe two applications or pieces of code
506
+ declare the same entity with different attributes. Note that different AMQP client libraries historically use slightly different defaults for
507
+ entities and this may cause attribute mismatches.
508
+ </li>
509
+ <li>{AMQP::Channel#tx_commit} or {AMQP::Channel#tx_rollback} might be run on a channel that wasn't previously made transactional with {AMQP::Channel#tx_select}</li>
510
+ </ul>
511
+ </dd>
512
+
513
+ <dt>Example RabbitMQ error message</dt>
514
+ <dd>
515
+ <ul>
516
+ <li>PRECONDITION_FAILED - parameters for queue 'amqpgem.examples.channel_exception' in vhost '/' not equivalent</li>
517
+ <li>PRECONDITION_FAILED - channel is not transactional</li>
518
+ </ul>
519
+ </dd>
520
+ </dl>
521
+
522
+ h4. 405 Resource Locked
523
+
524
+ <dl>
525
+ <dt>Description</dt>
526
+ <dd>The client attempted to work with a server entity to which it has no access because another client is working with it.</dd>
527
+
528
+ <dt>What might cause it</dt>
529
+ <dd>
530
+ <ul>
531
+ <li>Multiple applications (or different pieces of code/threads/processes/routines within a single application) might try to declare queues with the same name as exclusive.</li>
532
+ <li>Multiple consumer across multiple or single app might be registered as exclusive for the same queue.</li>
533
+ </ul>
534
+ </dd>
535
+
536
+ <dt>Example RabbitMQ error message</dt>
537
+ <dd>RESOURCE_LOCKED - cannot obtain exclusive access to locked queue 'amqpgem.examples.queue' in vhost '/'</dd>
538
+ </dl>
539
+
540
+
541
+ h4. 403 Access Refused
542
+
543
+ <dl>
544
+ <dt>Description</dt>
545
+ <dd>The client attempted to work with a server entity to which it has no access due to security settings. </dd>
546
+
547
+ <dt>What might cause it</dt>
548
+ <dd>Application tries to access a queue or exchange it has no permissions for (or right kind of permissions, for example, write permissions)</dd>
549
+
550
+ <dt>Example RabbitMQ error message</dt>
551
+ <dd>ACCESS_REFUSED - access to queue 'amqpgem.examples.channel_exception' in vhost 'amqp_gem_testbed' refused for user 'amqp_gem_reader'</dd>
552
+ </dl>
553
+
554
+
555
+
556
+
557
+ h2. TLS (SSL) related issues
220
558
 
221
559
  TBD
222
560
 
223
561
 
224
562
 
563
+
564
+
225
565
  h2. Conclusion
226
566
 
567
+ Distributed applications introduce a whole new class of failres developers need to be aware of. Many of them come from
568
+ unreliability of the network. The famous "Fallacies of Distributed Computing":http://en.wikipedia.org/wiki/Fallacies_of_Distributed_Computing list
569
+ common assumptions software engineers must not make:
570
+
571
+ * The network is reliable.
572
+ * Latency is zero.
573
+ * Bandwidth is infinite.
574
+ * The network is secure.
575
+ * Topology doesn't change.
576
+ * There is one administrator.
577
+ * Transport cost is zero.
578
+ * The network is homogeneous.
579
+
580
+ Unfortunately, applications that use Ruby and AMQP are not immune to these problems and developers need to always keep that
581
+ in mind. This list is just as relevant in 2011 as it was in the 90s.
582
+
583
+ Ruby amqp gem 0.8.x and later lets applications to define handlers that handle connection-level exceptions, channel-level
584
+ exceptions and TCP connection failures. Handling AMQP exceptions and network connection failures is relatively easy.
585
+ Re-declaring AMQP instances application works with is where the most of complexity comes from. By using Ruby objects as
586
+ error handlers, declaration of AMQP entities can be done in one place, making it much easier to understand and maintain.
587
+
588
+ amqp gem error handling and interruption is not a copy of RabbitMQ Java client's "Shutdown Protocol":http://www.rabbitmq.com/api-guide.html#shutdown,
589
+ but they turn out to be similar with respect to network failures and connection-level exceptions.
590
+
227
591
  TBD
228
592
 
229
593
 
230
594
 
231
595
  h2. Tell us what you think!
232
596
 
233
- Please take a moment and tell us what you think about this guide on "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp:
597
+ Please take a moment and tell us what you think about this guide "on Twitter":http://twitter.com/rubyamqp or "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp:
234
598
  what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is
235
599
  key to making documentation better.
236
600