amqp 0.8.0.rc2 → 0.8.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +2 -3
  2. data/.travis.yml +5 -2
  3. data/.yardopts +2 -0
  4. data/CHANGELOG +17 -20
  5. data/Gemfile +7 -5
  6. data/README.textile +67 -29
  7. data/Rakefile +6 -0
  8. data/amqp.gemspec +5 -5
  9. data/docs/08Migration.textile +27 -0
  10. data/docs/Bindings.textile +27 -0
  11. data/docs/ConnectingToTheBroker.textile +277 -0
  12. data/docs/DocumentationGuidesIndex.textile +25 -0
  13. data/docs/Durability.textile +27 -0
  14. data/docs/ErrorHandling.textile +84 -0
  15. data/docs/Exchanges.textile +27 -0
  16. data/docs/GettingStarted.textile +585 -0
  17. data/docs/Queues.textile +27 -0
  18. data/docs/RabbitMQVersions.textile +12 -2
  19. data/docs/Routing.textile +27 -0
  20. data/docs/TLS.textile +27 -0
  21. data/docs/VendorSpecificExtensions.textile +11 -1
  22. data/examples/{various → channels}/open_channel_without_assignment.rb +0 -4
  23. data/examples/channels/prefetch_as_constructor_argument.rb +31 -0
  24. data/examples/channels/qos_aka_prefetch.rb +34 -0
  25. data/examples/channels/qos_aka_prefetch_without_callback.rb +32 -0
  26. data/examples/error_handling/channel_level_exception.rb +47 -0
  27. data/examples/error_handling/channel_level_exception_with_multiple_channels_involved.rb +54 -0
  28. data/examples/error_handling/connection_loss_handler.rb +39 -0
  29. data/examples/error_handling/global_channel_level_exception_handler.rb +65 -0
  30. data/examples/error_handling/handling_authentication_failure_with_a_callback.rb +33 -0
  31. data/examples/error_handling/tcp_connection_failure_handling_with_a_rescue_block.rb +30 -0
  32. data/examples/error_handling/tcp_connection_failure_with_a_callback.rb +28 -0
  33. data/examples/{various → exchanges}/declare_an_exchange_without_assignment.rb +0 -4
  34. data/examples/guides/getting_started/01_hello_world.rb +24 -0
  35. data/examples/guides/getting_started/02_hello_world_dslified.rb +23 -0
  36. data/examples/guides/getting_started/03_babblr.rb +33 -0
  37. data/examples/guides/getting_started/04_weathr.rb +56 -0
  38. data/examples/hello_world.rb +12 -13
  39. data/examples/hello_world_with_eventmachine_in_a_separate_thread.rb +37 -0
  40. data/examples/{various → legacy}/ack.rb +0 -0
  41. data/examples/{various → legacy}/callbacks.rb +0 -0
  42. data/examples/{various → legacy}/clock.rb +0 -0
  43. data/examples/{various → legacy}/hashtable.rb +0 -0
  44. data/examples/{various → legacy}/logger.rb +0 -0
  45. data/examples/{various → legacy}/multiclock.rb +0 -0
  46. data/examples/{various → legacy}/pingpong.rb +0 -2
  47. data/examples/{various → legacy}/primes-simple.rb +0 -0
  48. data/examples/{various → legacy}/primes.rb +0 -2
  49. data/examples/{various → legacy}/stocks.rb +0 -0
  50. data/examples/{various → queues}/automatic_binding_for_default_direct_exchange.rb +4 -0
  51. data/examples/{various → queues}/basic_get.rb +0 -2
  52. data/examples/{various → queues}/declare_a_queue_without_assignment.rb +0 -4
  53. data/examples/queues/declare_and_bind_a_server_named_queue.rb +43 -0
  54. data/examples/{various → queues}/queue_status.rb +3 -8
  55. data/examples/{various → routing}/pubsub.rb +0 -0
  56. data/examples/{various → routing}/weather_updates.rb +1 -1
  57. data/lib/amqp/channel.rb +231 -52
  58. data/lib/amqp/client.rb +6 -3
  59. data/lib/amqp/connection.rb +9 -10
  60. data/lib/amqp/deprecated/fork.rb +3 -3
  61. data/lib/amqp/deprecated/logger.rb +1 -0
  62. data/lib/amqp/deprecated/mq.rb +23 -1
  63. data/lib/amqp/deprecated/rpc.rb +1 -0
  64. data/lib/amqp/exceptions.rb +45 -3
  65. data/lib/amqp/exchange.rb +29 -35
  66. data/lib/amqp/ext/em.rb +0 -7
  67. data/lib/amqp/ext/emfork.rb +3 -2
  68. data/lib/amqp/header.rb +4 -0
  69. data/lib/amqp/queue.rb +96 -33
  70. data/lib/amqp/session.rb +140 -0
  71. data/lib/amqp/version.rb +6 -1
  72. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +7 -7
  73. data/spec/integration/channel_level_exception_with_multiple_channels_spec.rb +69 -0
  74. data/spec/integration/declare_and_immediately_bind_a_server_named_queue_spec.rb +42 -0
  75. data/spec/integration/queue_declaration_spec.rb +8 -24
  76. data/spec/integration/queue_redeclaration_with_incompatible_attributes_spec.rb +43 -0
  77. data/spec/unit/amqp/connection_spec.rb +1 -1
  78. metadata +200 -182
  79. data/lib/amqp/basic_client.rb +0 -27
data/.gitignore CHANGED
@@ -8,8 +8,7 @@
8
8
  Gemfile.lock
9
9
 
10
10
  spec/amqp.yml
11
- vendor/bundle
12
- vendor/cache
11
+ vendor
13
12
 
14
13
  .yardoc/*
15
- doc/*
14
+ doc/*
@@ -1,7 +1,10 @@
1
- script: "bundle exec rspec spec"
1
+ script: "bundle exec rake spec:ci"
2
2
  rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
5
  - ree
6
6
  - rbx
7
- - jruby
7
+ - jruby
8
+ gemfile:
9
+ - Gemfile
10
+ - gemfiles/eventmachine-pre
data/.yardopts CHANGED
@@ -1,6 +1,8 @@
1
1
  --no-private
2
2
  --protected
3
3
  --markup="textile" lib/**/*.rb
4
+ --main README.textile
4
5
  -
5
6
  LICENSE
7
+ CHANGELOG
6
8
  docs/*.textile
data/CHANGELOG CHANGED
@@ -1,35 +1,32 @@
1
1
  = Version 0.8.0
2
2
 
3
- * [API] AMQP::Exchange#initialize now accepts :arguments option that takes a hash. Brokers
4
- may implement AMQP extensions using (usually x-prefixed) declaration arguments.
5
- * [API] AMQP::Queue#initialize now accepts :arguments option that takes a hash. RabbitMQ
6
- recognizes x-message-ttl argument and uses it as message TTL in milliseconds for
7
- queue that is being declared.
3
+ * [FEATURE] AMQP 0.9.1 support, including tx.* operations class.
4
+ * [API] AMQP::Channel#initialize now takes 3rd (optional) options hash.
5
+ * [API] Broker connection class is now AMQP::Session.
6
+ * [API] AMQP::Error instance now may carry cause, an exception that caused exception in question to be raised.
7
+ * [API] When initial TCP connection fails, default action is now to raise AMQP::TCPConnectionFailed.
8
+ * [API] AMQP::BasicClient#reconnect now takes 2nd optional argument, period of waiting in seconds.
9
+ * [FEATURE] Handlers for initial connection failre, connection loss; channel-level exceptions handlers on Channel instances.
10
+ * [API] AMQP::Exchange#initialize now accepts :arguments option that takes a hash.
11
+ * [API] AMQP::Queue#initialize now accepts :arguments option that takes a hash.
8
12
  * [API] AMQP#Logger is deprecated. It will be removed before 1.0 release.
9
13
  * [API] AMQP#fork is deprecated. It will be removed before 1.0 release.
10
14
  * [API] AMQP::RPC is deprecated. It will be removed before 1.0 release.
11
- * [FEATURE] Significant improvements to the documentation
15
+ * [FEATURE] Significant improvements to the documentation. From now on lack of/poor documentation is considered a severe bug.
12
16
  * [FEATURE] Support for RabbitMQ extensions to AMQP 0.9.1
13
- * [API] AMQP::Exchange#publish now accepts (an optional) block that is called as soon as message
14
- is considered published (EventMachine loop has pushed payload down the network stack).
15
- * [API] AMQP::Channel.new now accepts (an optional) block and yields newly opened channel to it as soon as
16
- channel.open-ok arrives from the broker.
17
+ * [API] AMQP::Exchange#publish now accepts (an optional) callback.
18
+ * [API] AMQP::Channel.new now accepts (an optional) callback.
17
19
  * [API] AMQP::Header#ack now can acknowledge multiple deliveries
18
20
  * [API] AMQP::Exchange#delete now takes (an optional) block that is called when exchange.delete-ok response arrives.
19
21
  * [API] AMQP::Header now implements #to_hash
20
22
  * [API] AMQP::Queue#pop block now can take 1, 2 or 3 arguments.
21
- 1 argument means handler is only interested in content payload
22
- 2 arguments mean handler is interested in headers and the content
23
- 3 arguments mean handler is interested in headers, content and AMQP method instance
24
23
  * [API] AMQP::Queue#purge now takes an optional block which is called when queue.purge-ok response arrives.
25
24
  * [API] AMQP::Queue#delete now takes an optional block which is called when queue.delete-ok response arrives.
26
25
  * [API] AMQP::Queue#delete now accepts :nowait option.
27
26
  * [API] AMQP::Queue#unbind now takes an optional block which is called when queue.unbind-ok response arrives.
28
27
  * [API] AMQP::Queue#unbind now accepts :routing_key as alias to :key. we believe it is a good idea to use AMQP terms.
29
- * [API] AMQP::Channel#prefetch now takes (an optional) 2nd parameter that specifies
30
- that QoS settings should be applied to underlying connection, as well as optional callback.
31
- * [API] AMQP::Channel#recover now takes (an optional) callback that is called when
32
- basic.recover-ok is received.
28
+ * [API] AMQP::Channel#prefetch now takes (an optional) 2nd parameter that specifies that QoS settings should be applied to underlying connection, as well as optional callback.
29
+ * [API] AMQP::Channel#recover now takes (an optional) callback that is called when basic.recover-ok is received.
33
30
  * [API] AMQP::Frame is gone.
34
31
  * [API] AMQP::Buffer is gone. Serialization & framing are now handled primarily by amq-protocol.
35
32
  * [FEATURE] AMQP gem is now AMQP 0.9.1 compatible: it runs atop of amq-client gem
@@ -40,11 +37,11 @@
40
37
 
41
38
  * [BUG] AMQP gem no longer conflicts with Builder 2.1.2 on Ruby 1.9.
42
39
  All Ruby on Rails 3 users who run Ruby 1.9 are highly recommended
43
- to upgrade!
40
+ to upgrade!
44
41
  * [API] AMQP::Exchange.default no longer caches exchange object between calls
45
42
  because it may lead to very obscure issues when channel that exchange was
46
- using is closed (due to connection loss, as part of test suite teardown
47
- or in any other way).
43
+ using is closed (due to connection loss, as part of test suite teardown
44
+ or in any other way).
48
45
 
49
46
  * [API] AMQP::Exchange.default now accepts channel as a parameter.
50
47
  * [API] AMQP::Exchange#channel
data/Gemfile CHANGED
@@ -1,18 +1,19 @@
1
1
  # encoding: utf-8
2
2
 
3
- source "http://gemcutter.org"
3
+ source :rubygems
4
4
 
5
5
  # Use local clones if possible.
6
+ # If you want to use your local copy, just symlink it to vendor.
6
7
  def custom_gem(name, options = Hash.new)
7
- local_path = File.expand_path("../../#{name}", __FILE__)
8
- if ENV["USE_AMQP_CUSTOM_GEMS"] && File.directory?(local_path)
8
+ local_path = File.expand_path("../vendor/#{name}", __FILE__)
9
+ if File.exist?(local_path)
9
10
  gem name, options.merge(:path => local_path).delete_if { |key, _| [:git, :branch].include?(key) }
10
11
  else
11
12
  gem name, options
12
13
  end
13
14
  end
14
15
 
15
- gem "eventmachine"
16
+ custom_gem "eventmachine"
16
17
  gem "json", :platform => :ruby_18
17
18
  custom_gem "amq-client", :git => "git://github.com/ruby-amqp/amq-client.git", :branch => "master"
18
19
  custom_gem "amq-protocol", :git => "git://github.com/ruby-amqp/amq-protocol.git", :branch => "master"
@@ -27,6 +28,7 @@ group(:development) do
27
28
  end
28
29
 
29
30
  group(:test) do
30
- gem "rspec", ">=2.0.0"
31
+ gem "rspec", ">=2.5.0"
32
+ gem "rake"
31
33
  custom_gem "evented-spec", :git => "git://github.com/ruby-amqp/evented-spec.git", :branch => "master"
32
34
  end
@@ -1,11 +1,16 @@
1
1
  h1. About amqp gem "!http://travis-ci.org/ruby-amqp/amqp.png!":http://travis-ci.org/ruby-amqp/amqp
2
2
 
3
- amqp gem is a widely used, feature-rich asynchronous Ruby AMQP client built on top of "EventMachine":http://rubyeventmachine.com.
3
+ amqp gem is a widely used, feature-rich, well-maintained asynchronous AMQP 0.9.1 client with batteries included.
4
4
  This library works with Ruby 1.8.7, Ruby 1.9.2, JRuby, REE and Rubinius, and is
5
5
  licensed under the "Ruby License":http://www.ruby-lang.org/en/LICENSE.txt.
6
6
  Versions 0.8.0 and later of amqp gem implement "AMQP 0.9.1":http://bit.ly/hw2ELX.
7
7
 
8
8
 
9
+ h2. I know what AMQP is, how do I get started?
10
+
11
+ See "Getting started with amqp gem" and "Documentation: tutorials, guides & API reference" sections below.
12
+
13
+
9
14
  h2. What is AMQP?
10
15
 
11
16
  AMQP is an "open standard for messaging middleware":http://www.amqp.org/confluence/display/AMQP/About+AMQP that
@@ -32,7 +37,7 @@ Specific examples:
32
37
  there are some new results.
33
38
 
34
39
  * Content aggregators may update full-text search and geospatial search indexes
35
- by delegating actual indexing work to other applications over AMQP.
40
+ by delegating actual indexing work to other applications over AMQP.
36
41
 
37
42
  * Companies may provide "Firehose-like" push APIs to their customers, partners
38
43
  or just general public.
@@ -42,11 +47,11 @@ Specific examples:
42
47
 
43
48
  * An application that watches updates from a real-time stream (be it markets data
44
49
  or Twitter stream) can propagate updates to interested parties, including
45
- Web applications that display that information in the real time.
50
+ Web applications that display that information in the real time.
46
51
 
47
52
 
48
53
 
49
- h2. Getting started with amqp gem
54
+ h2(Getting_started_with_amqp_gem). Getting started with amqp gem
50
55
 
51
56
  h3. Install RabbitMQ
52
57
 
@@ -62,37 +67,77 @@ h3. Install the gem
62
67
 
63
68
  h3. "Hello, World" example
64
69
 
65
- <pre>
70
+ <pre><code>
66
71
  #!/usr/bin/env ruby
67
72
  # encoding: utf-8
68
73
 
69
74
  require "rubygems"
75
+ # or
76
+ #
77
+ # require "bundler"
78
+ # Bundler.setup
79
+ #
80
+ # if you use Bundler
81
+
70
82
  require 'amqp'
71
83
 
72
84
  EventMachine.run do
73
- AMQP.connect(:host => 'localhost') do |connection|
74
- puts "Connected to AMQP broker"
85
+ connection = AMQP.connect(:host => '127.0.0.1')
86
+ puts "Connected to AMQP broker. Running #{AMQP::VERSION} version of the gem..."
75
87
 
76
- channel = AMQP::Channel.new(connection)
77
- queue = channel.queue("amqpgem.examples.hello_world")
78
- exchange = channel.default_exchange
88
+ channel = AMQP::Channel.new(connection)
89
+ queue = channel.queue("amqpgem.examples.hello_world", :auto_delete => true)
90
+ exchange = channel.direct("")
79
91
 
80
- queue.subscribe do |payload|
81
- puts "Received a message: #{payload}. Disconnecting..."
92
+ queue.subscribe do |payload|
93
+ puts "Received a message: #{payload}. Disconnecting..."
82
94
 
83
- connection.close {
84
- EM.stop { exit }
85
- }
86
- end
95
+ connection.close {
96
+ EM.stop { exit }
97
+ }
98
+ end
87
99
 
88
- exchange.publish "Hello, world!", :routing_key => queue.name
89
- end
100
+ exchange.publish "Hello, world!", :routing_key => queue.name
90
101
  end
91
- </pre>
102
+ </code></pre>
92
103
 
93
104
  (see "as a Gist":https://gist.github.com/910211)
94
105
 
95
106
 
107
+
108
+ h2(#Documentation_tutorials_guides_API_reference). Documentation: tutorials, guides & API reference
109
+
110
+ We believe that in order to be the best Ruby AMQP client out there, we need to care about documentation as much as
111
+ code readability, API beauty and autotomated testing across 5 Ruby implementations on 3 operating systems.
112
+
113
+
114
+ h3. Tutorials
115
+
116
+ We have written and maintain "Getting started guide":http://rdoc.info/github/ruby-amqp/amqp/master/file/docs/GettingStarted.textile that is written in form of a tutorial.
117
+ Check it out! If something isn't clear, every guide explains how to contact documentation authors.
118
+
119
+
120
+ h3. Examples
121
+
122
+ You can find many examples (both real-world cases and simple demonstrations)
123
+ under "examples directory":https://github.com/ruby-amqp/amqp/tree/master/examples in the repository.
124
+ Note that those examples are written against version 0.8.0.rc1 and later. 0.6.x and 0.7.x
125
+ may not support certain AMQP protocol or "DSL syntax" features.
126
+
127
+
128
+ h3. Guides
129
+
130
+ "Documentation guides":http://rdoc.info/github/ruby-amqp/amqp/master/file/docs/DocumentationGuidesIndex.textile describe
131
+ the library itself as well as AMQP usage scenarios, routing, error handing & recovery, broker-specific extensions, TLS support and so on.
132
+
133
+
134
+ h3. API reference
135
+
136
+ "Reference documentation":http://rdoc.info/github/ruby-amqp/amqp/master/frames is up on rdoc.info and is updated daily.
137
+
138
+ *If you don't find your answer in documentation, we consider it a high severity bug* that you should "file to us":http://github.com/ruby-amqp/amqp/issues.
139
+
140
+
96
141
  h2. How to use AMQP gem with Ruby on Rails, Merb, Sinatra and other web frameworks
97
142
 
98
143
  To use AMQP gem from web applications, you would need to have EventMachine reactor running.
@@ -141,13 +186,6 @@ gem "amqp", :git => "git://github.com/ruby-amqp/amqp.git", :branch => "master"
141
186
 
142
187
 
143
188
 
144
- h2. Examples
145
-
146
- You can find many examples (both real-world cases and simple demonstrations)
147
- under "examples directory":https://github.com/ruby-amqp/amqp/tree/master/examples in the repository.
148
-
149
-
150
-
151
189
  h2. How does amqp gem relate to amq-client gem, amq-protocol and libraries like bunny?
152
190
 
153
191
  See "this page about AMQP gems family":https://github.com/ruby-amqp/amq-client/blob/master/README.textile
@@ -209,7 +247,7 @@ use version 0.7.
209
247
 
210
248
  h2. Links
211
249
 
212
- * "API Documentation":http://rdoc.info/github/ruby-amqp/amq-protocol/master/frames
250
+ * "API reference":http://rdoc.info/github/ruby-amqp/amqp/master/frames
213
251
  * "Examples":https://github.com/ruby-amqp/amq-protocol/tree/master/examples/
214
- * "Issue tracker":http://github.com/ruby-amqp/amq-protocol/issues
215
- * "Continous integration server":http://travis-ci.org/#!/ruby-amqp/amqp
252
+ * "Issue tracker":http://github.com/ruby-amqp/amqp/issues
253
+ * "Continous integration server":http://travis-ci.org/#!/ruby-amqp/amqp
data/Rakefile CHANGED
@@ -1,8 +1,14 @@
1
+ require 'fileutils'
1
2
  require 'rspec/core/rake_task'
2
3
 
3
4
  desc "Run spec suite (uses Rspec2)"
4
5
  RSpec::Core::RakeTask.new(:spec) { |t|}
5
6
 
7
+ namespace :spec do
8
+ desc "Clean up rbx compiled files and run spec suite"
9
+ RSpec::Core::RakeTask.new(:ci) { |t| Dir.glob("**/*.rbc").each {|f| FileUtils.rm_f(f) } }
10
+ end
11
+
6
12
  desc "Run specs with RCov"
7
13
  RSpec::Core::RakeTask.new(:rcov) do |t|
8
14
  t.rcov = true
@@ -10,22 +10,22 @@ Gem::Specification.new do |s|
10
10
  s.authors = ["Aman Gupta", "Jakub Stastny aka botanicus", "Michael S. Klishin"]
11
11
  s.homepage = "http://github.com/ruby-amqp/amqp"
12
12
  s.summary = "AMQP client implementation in Ruby/EventMachine."
13
- s.description = "Asynchronous AMQP 0.9.1 client for Ruby. Built on top of Eventmachine."
13
+ s.description = "Widely used, feature-rich asynchronous AMQP 0.9.1 client with batteries included"
14
14
  s.cert_chain = nil
15
15
  s.email = ["bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=\n", "c3Rhc3RueUAxMDFpZGVhcy5jeg==\n"].map { |i| Base64.decode64(i) }
16
16
 
17
17
  # files
18
- s.files = `git ls-files`.split("\n").reject { |file| file =~ /^vendor\// }
18
+ s.files = `git ls-files`.split("\n").reject { |file| file =~ /^vendor\// || file =~ /^gemfiles\// }
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  # RDoc
22
22
  s.has_rdoc = true
23
23
  s.rdoc_options = '--include=examples --main README.textile'
24
- s.extra_rdoc_files = ["README.textile"] + Dir.glob("doc/*")
24
+ s.extra_rdoc_files = ["README.textile"] + Dir.glob("docs/*")
25
25
 
26
26
  # Dependencies
27
- s.add_dependency "eventmachine", "~> 0.12.10"
28
- s.add_dependency "amq-client", ">= 0.7.0.alpha2"
27
+ s.add_dependency "eventmachine"
28
+ s.add_dependency "amq-client", ">= 0.7.0.alpha13"
29
29
 
30
30
  begin
31
31
  require "changelog"
@@ -0,0 +1,27 @@
1
+ h1. TBD
2
+
3
+
4
+ h2. About this guide
5
+
6
+ TBD
7
+
8
+
9
+ h2. Covered versions
10
+
11
+ This guide covers amqp gem v0.8.0 and later.
12
+
13
+
14
+
15
+ h2. TBD
16
+
17
+ TBD
18
+
19
+
20
+
21
+ h2. Tell us what you think!
22
+
23
+ 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:
24
+ what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is
25
+ key to making documentation better.
26
+
27
+ 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
@@ -0,0 +1,27 @@
1
+ h1. TBD
2
+
3
+
4
+ h2. About this guide
5
+
6
+ TBD
7
+
8
+
9
+ h2. Covered versions
10
+
11
+ This guide covers amqp gem v0.8.0 and later.
12
+
13
+
14
+
15
+ h2. TBD
16
+
17
+ TBD
18
+
19
+
20
+
21
+ h2. Tell us what you think!
22
+
23
+ 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:
24
+ what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is
25
+ key to making documentation better.
26
+
27
+ 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
@@ -0,0 +1,277 @@
1
+ h1. Connecting to the broker
2
+
3
+
4
+ h2. About this guide
5
+
6
+ This guide covers connection to AMQP broker from standalone and Web applications,
7
+ connection error handling, authentication failure handling and related issues..
8
+
9
+
10
+ h2. Covered versions
11
+
12
+ This guide covers amqp gem v0.8.0 and later.
13
+
14
+
15
+
16
+ h2. Terminology
17
+
18
+ In this guide we define standalone application as application that does not run on
19
+ a Web server like Unicorn or Passenger. The key difference is that these applications
20
+ control main Ruby VM thread and often use it to run EventMachine event loop. When
21
+ amqp gem is used inside of a Web applications, main thread is occupied by Web application
22
+ server and code required to establish connection to AMQP broker needs to be a little
23
+ bit different.
24
+
25
+
26
+
27
+ h2. In standalone applications
28
+
29
+ h3. EventMachine event loop
30
+
31
+ amqp gem uses "EventMachine":http://rubyeventmachine.com under the hood and needs EventMachine
32
+ event loop to be running in order to connect to AMQP broker or send any data. This means that
33
+ before connecting to AMQP broker, we need to _start EventMachine reactor_ (get the event loop
34
+ going). Here is how to do it:
35
+
36
+ <pre>
37
+ <code>
38
+ require "amqp"
39
+
40
+ EventMachine.run do
41
+ # ...
42
+ end
43
+ </code>
44
+ </pre>
45
+
46
+ "EventMachine.run":http://eventmachine.rubyforge.org/EventMachine.html#M000461 will block current thread until event loop is stopped.
47
+ Standalone applications often can afford starting event loop on the main thread. If you have no experience with threading, this is a
48
+ recommended way.
49
+
50
+
51
+ h3. AMQP.connect with a block
52
+
53
+ Once event loop is running, {AMQP.connect} method will attempt to connect to the broker. It can be used in two ways. Here is the
54
+ first one:
55
+
56
+ <pre>
57
+ <code>
58
+ require "amqp"
59
+
60
+ EventMachine.run do
61
+ # using AMQP.connect with a block
62
+ AMQP.connect(:host => "localhost") do |client|
63
+ # connection is open and ready to be used
64
+ end
65
+ end
66
+ </code>
67
+ </pre>
68
+
69
+ {AMQP.connect} takes a block that will be executed as soon as AMQP connection is open (TCP connection was set up,
70
+ authentication succeeded, broker and client finished negotiating connection parameters like max frame size).
71
+
72
+
73
+ h3. AMQP.connect without a callback
74
+
75
+ Alternative way of connecting is this:
76
+
77
+ <pre>
78
+ <code>
79
+ require "amqp"
80
+
81
+ EventMachine.run do
82
+ # using AMQP.connect with a block
83
+ client = AMQP.connect(:host => "hub.megacorp.internal", :username => "hedgehog", :password => "t0ps3kr3t")
84
+ # connection is not yet open, however, amqp gem will delay
85
+ # channel operations until after connection is open. However,
86
+ # amqp gem cannot solve every possible race condition so be careful
87
+ end
88
+ </code>
89
+ </pre>
90
+
91
+ If you do not need to assign returned value to a variable, "block version" is recommended because it eliminates issues that may
92
+ arise from attempts to use a connection object that is not fully opened yet. For example, handling of authentication failures is simpler
93
+ with the block version, as we will see in the following sections.
94
+
95
+
96
+ h3. AMQP.start
97
+
98
+ EventMachine.run and {AMQP.connect} with a block is such a common combination that amqp gem provides a shortcut:
99
+
100
+ <pre>
101
+ <code>
102
+ require "amqp"
103
+
104
+ AMQP.start("amqp://dev.rabbitmq.com:5672/") do |client|
105
+ # connection is open and ready to be used
106
+ end
107
+ </code>
108
+ </pre>
109
+
110
+ As these examples demonstrate, {AMQP.connect} and {AMQP.start} accept either a Hash of connection options or a connection URI string.
111
+ See reference documentation for each method to learn all the options they accept and what the default values are.
112
+
113
+
114
+ h3. On Thread#sleep use
115
+
116
+ When not passing a block to {AMQP.connect}, it is tempting to "give connection some time to get through" by using Thread#sleep. Unless you are
117
+ running event loop in a separate thread, don't do this. Thread#sleep blocks current thread so if event loop is running the very same current thread,
118
+ blocking it _will also block the event loop_. *When event loop is blocked, no data is sent or received, so connection does not proceed.*
119
+
120
+
121
+ h3. Detecting TCP connection failures
122
+
123
+ When applications connect to the broker, they need to handle connection failures. Networks are not 100% reliable, even with modern system configuration tools
124
+ 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
125
+ TCP connection failure, the first one is to catch an exception:
126
+
127
+ <pre>
128
+ <code>
129
+ #!/usr/bin/env ruby
130
+ # encoding: utf-8
131
+
132
+ require "rubygems"
133
+ require "amqp"
134
+
135
+
136
+ puts "=> TCP connection failure handling with a rescue statement"
137
+ puts
138
+
139
+ connection_settings = {
140
+ :port => 9689,
141
+ :vhost => "/amq_client_testbed",
142
+ :user => "amq_client_gem",
143
+ :password => "amq_client_gem_password",
144
+ :timeout => 0.3
145
+ }
146
+
147
+ begin
148
+ AMQP.start(connection_settings) do |connection, open_ok|
149
+ raise "This should not be reachable"
150
+ end
151
+ rescue AMQP::TCPConnectionFailed => e
152
+ puts "Caught AMQP::TCPConnectionFailed => TCP connection failed, as expected."
153
+ end
154
+ </code>
155
+ </pre>
156
+
157
+ {AMQP.connect} (and, subsequentily, {AMQP.start}) will raise {AMQP::TCPConnectionFailed} if connection fails. Code that catches it can write to log
158
+ 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
159
+ to the same endpoint (hostname, port, vhost combination) will result in the same issue over and over. TBD: failover, connection to the cluster.
160
+
161
+ Alternative way of handling connection failure is with an errback (a callback for specific kind of error):
162
+
163
+ <pre>
164
+ <code>
165
+ #!/usr/bin/env ruby
166
+ # encoding: utf-8
167
+
168
+ require "rubygems"
169
+ require "amqp"
170
+
171
+ puts "=> TCP connection failure handling with a callback"
172
+ puts
173
+
174
+ handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop }
175
+ connection_settings = {
176
+ :port => 9689,
177
+ :vhost => "/amq_client_testbed",
178
+ :user => "amq_client_gem",
179
+ :password => "amq_client_gem_password",
180
+ :timeout => 0.3,
181
+ :on_tcp_connection_failure => handler
182
+ }
183
+
184
+
185
+ AMQP.start(connection_settings) do |connection, open_ok|
186
+ raise "This should not be reachable"
187
+ end
188
+ </code>
189
+ </pre>
190
+
191
+ :on_tcp_connection_failure option accepts any object that responds to #call.
192
+
193
+ 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
194
+ instead of a Proc.
195
+
196
+ TBD: provide an example
197
+
198
+
199
+ h3. Detecting authentication failures
200
+
201
+ Another reason why connection may fail is authentication failure. Handling authentication failure is very similar to handling initial TCP
202
+ connection failure:
203
+
204
+ <pre>
205
+ <code>
206
+ #!/usr/bin/env ruby
207
+ # encoding: utf-8
208
+
209
+ require "rubygems"
210
+ require "amqp"
211
+
212
+ puts "=> TCP connection failure handling with a callback"
213
+ puts
214
+
215
+ handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop }
216
+ connection_settings = {
217
+ :port => 5672,
218
+ :vhost => "/amq_client_testbed",
219
+ :user => "amq_client_gem",
220
+ :password => "amq_client_gem_password_that_is_incorrect #{Time.now.to_i}",
221
+ :timeout => 0.3,
222
+ :on_tcp_connection_failure => handler,
223
+ :on_possible_authentication_failure => Proc.new { |settings|
224
+ puts "Authentication failed, as expected, settings are: #{settings.inspect}"
225
+
226
+ EM.stop
227
+ }
228
+ }
229
+
230
+ AMQP.start(connection_settings) do |connection, open_ok|
231
+ raise "This should not be reachable"
232
+ end
233
+ </code>
234
+ </pre>
235
+
236
+ In case you wonder why callback name has "possible" in it: {http://bit.ly/mTr1YN AMQP 0.9.1 spec} requires broker implementations to
237
+ simply close TCP connection without sending any more data when an exception (such as authentication failure) occurs before AMQP connection
238
+ is open. In practice, however, when broker closes TCP connection between successful TCP connection and before AMQP connection is open,
239
+ it means that authentication has failed.
240
+
241
+
242
+
243
+ h2. In Web applications (Ruby on Rails, Sinatra, Merb, Rack)
244
+
245
+ h3. With Unicorn
246
+
247
+ TBD
248
+
249
+
250
+ h3. With Thin
251
+
252
+ TBD
253
+
254
+
255
+ h3. With Goliath
256
+
257
+ TBD
258
+
259
+
260
+ h3. With Passenger
261
+
262
+ TBD
263
+
264
+
265
+
266
+ h2. What to read next
267
+
268
+ TBD
269
+
270
+
271
+ h2. Tell us what you think!
272
+
273
+ 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:
274
+ what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is
275
+ key to making documentation better.
276
+
277
+ 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