├── .gitignore ├── .rspec ├── .travis.yml ├── .yardopts ├── ChangeLog.md ├── Gemfile ├── README.md ├── Rakefile ├── amqp.gemspec ├── bin ├── ci │ └── before_build ├── cleanify.rb ├── docup ├── irb └── set_test_suite_realms_up.sh ├── docs ├── 08Migration.textile ├── AMQP091ModelExplained.textile ├── Bindings.textile ├── Clustering.textile ├── ConnectingToTheBroker.textile ├── ConnectionEncryptionWithTLS.textile ├── DocumentationGuidesIndex.textile ├── Durability.textile ├── ErrorHandling.textile ├── Exchanges.textile ├── GettingStarted.textile ├── PatternsAndUseCases.textile ├── Queues.textile ├── RabbitMQVersions.textile ├── RunningTests.textile ├── TestingWithEventedSpec.textile ├── Troubleshooting.textile ├── VendorSpecificExtensions.textile └── diagrams │ ├── 001_hello_world_example_routing.png │ ├── 002_blabbr_example_routing.png │ ├── 003_weathr_example_routing.png │ ├── 004_fanout_exchange.png │ ├── 005_direct_exchange.png │ ├── 006_amqp_091_message_acknowledgements.png │ ├── 007_rabbitmq_publisher_confirms.png │ └── redhat │ ├── direct_exchange.png │ ├── fanout_exchange.png │ └── topic_exchange.png ├── examples ├── channels │ ├── open_channel_with_one_arity_callback.rb │ ├── open_channel_without_assignment.rb │ ├── prefetch_as_constructor_argument.rb │ ├── qos_aka_prefetch.rb │ └── qos_aka_prefetch_without_callback.rb ├── connection │ └── connect_and_immediately_disconnect.rb ├── error_handling │ ├── automatic_recovery_of_channel_and_queues.rb │ ├── automatically_recovering_hello_world_consumer.rb │ ├── automatically_recovering_hello_world_consumer_that_uses_a_server_named_queue.rb │ ├── basic_connection_failover.rb │ ├── channel_level_exception.rb │ ├── channel_level_exception_with_multiple_channels_involved.rb │ ├── connection_level_exception.rb │ ├── connection_level_exception_with_objects.rb │ ├── connection_loss_handler.rb │ ├── global_channel_level_exception_handler.rb │ ├── handling_authentication_failure_with_a_callback.rb │ ├── handling_authentication_failure_with_a_rescue_block.rb │ ├── handling_vhost_misconfiguration_with_a_rescue_block.rb │ ├── hello_world_producer.rb │ ├── insufficient_permissions.rb │ ├── manual_connection_and_channel_recovery.rb │ ├── queue_exclusivity_violation.rb │ ├── queue_name_violation.rb │ ├── reopening_a_channel_after_channel_level_exception.rb │ ├── tcp_connection_failure_handling_with_a_rescue_block.rb │ └── tcp_connection_failure_with_a_callback.rb ├── exchanges │ ├── autodeletion_of_exchanges.rb │ └── declare_an_exchange_without_assignment.rb ├── extensions │ └── rabbitmq │ │ ├── connection_blocking.rb │ │ ├── per_queue_message_ttl.rb │ │ ├── publisher_confirmations_with_transient_messages.rb │ │ └── using_alternate_exchanges.rb ├── guides │ ├── getting_started │ │ ├── 01_hello_world.rb │ │ ├── 02_hello_world_dslified.rb │ │ ├── 03_blabbr.rb │ │ └── 04_weathr.rb │ └── queues │ │ ├── 01a_declaring_a_server_named_queue_using_queue_constructor.rb │ │ ├── 01b_declaring_a_queue_using_queue_constructor.rb │ │ ├── 02a_declaring_a_durable_shared_queue.rb │ │ ├── 02b_declaring_a_durable_shared_queue.rb │ │ ├── 03a_declaring_a_temporary_exclusive_queue.rb │ │ ├── 03b_declaring_a_temporary_exclusive_queue.rb │ │ ├── 04_bind_a_queue_using_exchange_instance.rb │ │ ├── 05_bind_a_queue_using_exchange_name.rb │ │ ├── 06_subscribe_to_receive_messages.rb │ │ ├── 07_fetch_a_message_from_the_queue.rb │ │ ├── 08_unsubscribing_a_consumer.rb │ │ ├── 09_unbinding_from_exchange.rb │ │ ├── 10_purge_a_queue.rb │ │ ├── 11_deleting_a_queue.rb │ │ ├── 12_objects_that_consume_messages.rb │ │ └── 13_objects_that_consume_messages_take_two.rb ├── hello_world.rb ├── hello_world_with_an_empty_string.rb ├── hello_world_with_eventmachine_in_a_separate_thread.rb ├── hello_world_with_large_payload.rb ├── inspecting_server_information.rb ├── issues │ ├── amq_client_issue_7.rb │ ├── amq_protocol_issue_14.rb │ ├── issue_121.rb │ ├── issue_75.rb │ ├── issue_79.rb │ ├── issue_80.rb │ ├── issue_93.rb │ └── issue_94.rb ├── patterns │ ├── command │ │ ├── consumer.rb │ │ └── producer.rb │ ├── event │ │ ├── consumer.rb │ │ └── producer.rb │ └── request_reply │ │ ├── client.rb │ │ └── server.rb ├── publishing │ ├── publishing_a_one_off_message.rb │ ├── publishing_callback.rb │ ├── returned_messages.rb │ └── simplistic_scatter_gather.rb ├── queues │ ├── accessing_message_metadata.rb │ ├── automatic_binding_for_default_direct_exchange.rb │ ├── basic_get.rb │ ├── cancel_default_consumer.rb │ ├── declare_a_queue_without_assignment.rb │ ├── declare_and_bind_a_server_named_queue.rb │ ├── queue_status.rb │ ├── rejecting_messages_without_requeueuing.rb │ └── using_explicit_acknowledgements.rb ├── rack │ └── publish_a_message_on_request │ │ └── thin.ru ├── routing │ ├── fanout_routing.rb │ ├── headers_routing.rb │ ├── pubsub.rb │ ├── round_robin_with_direct_exchange.rb │ ├── round_robin_with_the_default_exchange.rb │ ├── unroutable_mandatory_message_is_returned.rb │ └── weather_updates.rb ├── tls │ └── using_tls.rb └── tls_certificates │ ├── client │ ├── cert.pem │ ├── key.pem │ ├── keycert.p12 │ └── req.pem │ ├── server │ ├── cert.pem │ ├── key.pem │ ├── keycert.p12 │ └── req.pem │ └── testca │ ├── cacert.cer │ ├── cacert.pem │ ├── certs │ ├── 01.pem │ └── 02.pem │ ├── index.txt │ ├── index.txt.attr │ ├── index.txt.attr.old │ ├── index.txt.old │ ├── openssl.cnf │ ├── private │ └── cakey.pem │ ├── serial │ └── serial.old ├── gemfiles └── eventmachine-pre ├── lib ├── amq │ └── protocol │ │ └── get_response.rb ├── amqp.rb └── amqp │ ├── auth_mechanism_adapter.rb │ ├── auth_mechanism_adapter │ ├── external.rb │ └── plain.rb │ ├── bit_set.rb │ ├── broker.rb │ ├── callbacks.rb │ ├── channel.rb │ ├── channel_id_allocator.rb │ ├── compatibility │ └── ruby187_patchlevel_check.rb │ ├── consumer.rb │ ├── consumer_tag_generator.rb │ ├── deferrable.rb │ ├── entity.rb │ ├── exceptions.rb │ ├── exchange.rb │ ├── extensions │ └── rabbitmq.rb │ ├── framing │ └── string │ │ └── frame.rb │ ├── handlers_registry.rb │ ├── header.rb │ ├── int_allocator.rb │ ├── integration │ └── rails.rb │ ├── openable.rb │ ├── queue.rb │ ├── session.rb │ ├── settings.rb │ ├── utilities │ ├── event_loop_helper.rb │ └── server_type.rb │ └── version.rb ├── repl └── spec ├── integration ├── authentication_spec.rb ├── automatic_binding_for_default_direct_exchange_spec.rb ├── automatic_recovery_predicate_spec.rb ├── basic_get_spec.rb ├── basic_publish_with_message_framing_spec.rb ├── basic_return_spec.rb ├── channel_close_spec.rb ├── channel_level_exception_handling_spec.rb ├── channel_level_exception_with_multiple_channels_spec.rb ├── concurrent_publishing_on_a_shared_channel_spec.rb ├── connection_close_spec.rb ├── connection_level_exception_handling_spec.rb ├── declare_and_immediately_bind_a_server_named_queue_spec.rb ├── declare_one_hundred_server_named_queues_spec.rb ├── direct_exchange_routing_spec.rb ├── exchange_declaration_spec.rb ├── exchange_to_exchange_binding_spec.rb ├── extensions │ └── rabbitmq │ │ └── publisher_confirmations_spec.rb ├── fanout_exchange_routing_spec.rb ├── headers_exchange_routing_spec.rb ├── hello_world_spec.rb ├── mandatory_messages_spec.rb ├── message_acknowledgement_spec.rb ├── message_metadata_access_spec.rb ├── multiple_consumers_per_queue_spec.rb ├── ordering_of_published_messages_spec.rb ├── queue_declaration_spec.rb ├── queue_exclusivity_spec.rb ├── queue_redeclaration_with_incompatible_attributes_spec.rb ├── queue_status_spec.rb ├── recovery │ ├── per_channel_automatic_recovery_on_graceful_broker_shutdown_spec.rb │ └── per_channel_automatic_recovery_spec.rb ├── redelivery_of_unacknowledged_messages_spec.rb ├── regressions │ ├── concurrent_publishing_on_the_same_channel_spec.rb │ ├── empty_message_body_spec.rb │ └── issue66_spec.rb ├── remove_individual_binding_spec.rb ├── reply_queue_communication_spec.rb ├── store_and_forward_spec.rb ├── stress │ └── publishing_of_messages_with_incrementing_sizes_spec.rb ├── topic_subscription_spec.rb ├── tx_commit_spec.rb └── tx_rollback_spec.rb ├── spec_helper.rb └── unit └── amqp ├── channel_id_allocation_spec.rb └── connection_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /*.gem 2 | *.rbc 3 | .rbx/* 4 | ~* 5 | #* 6 | *~ 7 | .rvmrc 8 | .bundle 9 | Gemfile.lock 10 | 11 | spec/amqp.yml 12 | vendor 13 | 14 | .yardoc/* 15 | doc/* 16 | tmp/* 17 | bin/* 18 | .AppleDouble/* 19 | debug/* 20 | 21 | .ruby-version 22 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format 3 | progress 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | bundler_args: --without development 3 | before_script: ./bin/ci/before_build 4 | script: "bundle exec rake spec:ci" 5 | env: 6 | - CI=true 7 | rvm: 8 | - 2.3.3 9 | - 2.4.1 10 | gemfile: 11 | - Gemfile 12 | - gemfiles/eventmachine-pre 13 | notifications: 14 | recipients: 15 | - michael@rabbitmq.com 16 | branches: 17 | only: 18 | - master 19 | - 1.7.x-stable 20 | matrix: 21 | allow_failures: 22 | - rvm: jruby 23 | gemfile: gemfiles/eventmachine-pre 24 | 25 | services: 26 | - rabbitmq 27 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --no-private 2 | --protected 3 | --markup="textile" lib/**/*.rb 4 | --main README.md 5 | --asset docs:docs --asset examples:examples 6 | --hide-tag todo 7 | - 8 | LICENSE 9 | CHANGELOG 10 | docs/*.textile -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | source "https://rubygems.org" 4 | 5 | # Use local clones if possible. 6 | # If you want to use your local copy, just symlink it to vendor. 7 | def custom_gem(name, options = Hash.new) 8 | local_path = File.expand_path("../vendor/#{name}", __FILE__) 9 | if File.exist?(local_path) 10 | puts "Using #{name} from #{local_path}..." 11 | gem name, options.merge(path: local_path).delete_if { |key, _| [:git, :branch].include?(key) } 12 | else 13 | gem name, options 14 | end 15 | end 16 | 17 | custom_gem "eventmachine", "~> 1.2.7" 18 | custom_gem "amq-protocol", git: "https://github.com/ruby-amqp/amq-protocol.git", branch: "master" 19 | 20 | group :development do 21 | gem "yard", ">= 0.7.2" 22 | # yard tags this buddy along 23 | gem "RedCloth", platform: :mri 24 | 25 | platform :ruby do 26 | gem "rdiscount" 27 | 28 | # To test event loop helper and various Rack apps 29 | gem "thin" 30 | gem "unicorn" 31 | end 32 | end 33 | 34 | group :test do 35 | gem "rspec", "~> 2.14.1" 36 | gem "rake", "~> 12.0" 37 | 38 | custom_gem "evented-spec", git: "https://github.com/ruby-amqp/evented-spec.git", branch: "master" 39 | gem "effin_utf8" 40 | 41 | gem "multi_json" 42 | 43 | gem "json", platform: :jruby 44 | gem "yajl-ruby", platform: :ruby_18 45 | end 46 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'rspec/core/rake_task' 3 | 4 | desc "Run spec suite (uses Rspec2)" 5 | RSpec::Core::RakeTask.new(:spec) { |t|} 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 | 12 | desc "Run specs with RCov" 13 | RSpec::Core::RakeTask.new(:rcov) do |t| 14 | t.rcov = true 15 | t.rcov_opts = ['--exclude', 'spec'] 16 | end 17 | 18 | desc "Generate AMQP specification classes" 19 | task :codegen do 20 | sh 'ruby protocol/codegen.rb > lib/amqp/spec.rb' 21 | sh 'ruby lib/amqp/spec.rb' 22 | end 23 | 24 | desc "Build the gem" 25 | task :gem do 26 | sh 'gem build *.gemspec' 27 | end 28 | 29 | desc "Synonym for gem" 30 | task :pkg => :gem 31 | desc "Synonym for gem" 32 | task :package => :gem 33 | 34 | 35 | desc "Regenerate contributors file." 36 | task :contributors do 37 | authors = %x{git log | grep ^Author:}.split("\n") 38 | results = authors.reduce(Hash.new) do |results, line| 39 | name = line.sub(/^Author: (.+) <.+>$/, '\1') 40 | results[name] ||= 0 41 | results[name] += 1 42 | results 43 | end 44 | results = results.sort_by { |_, count| count }.reverse 45 | File.open("CONTRIBUTORS", "w") do |file| 46 | results.each do |name, count| 47 | file.puts "#{name}: #{count}" 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /amqp.gemspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env gem build 2 | # encoding: utf-8 3 | 4 | require "base64" 5 | require File.expand_path("../lib/amqp/version", __FILE__) 6 | 7 | Gem::Specification.new do |s| 8 | s.name = "amqp" 9 | s.version = AMQP::VERSION 10 | s.authors = ["Aman Gupta", "Jakub Stastny aka botanicus", "Michael S. Klishin"] 11 | s.homepage = "http://rubyamqp.info" 12 | s.summary = "Mature EventMachine-based RabbitMQ client" 13 | s.description = "Mature EventMachine-based RabbitMQ client." 14 | s.email = ["bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=\n", "c3Rhc3RueUAxMDFpZGVhcy5jeg==\n"].map { |i| Base64.decode64(i) } 15 | s.licenses = ["Ruby"] 16 | 17 | # files 18 | s.files = `git ls-files`.split("\n").reject { |file| file =~ /^vendor\// || file =~ /^gemfiles\// } 19 | s.require_paths = ["lib"] 20 | 21 | s.rdoc_options = '--include=examples --main README.md' 22 | s.extra_rdoc_files = ["README.md"] + Dir.glob("docs/*") 23 | 24 | # Dependencies 25 | s.add_dependency "eventmachine" 26 | s.add_dependency "amq-protocol", ">= 2.2.0" 27 | 28 | s.rubyforge_project = "amqp" 29 | end 30 | -------------------------------------------------------------------------------- /bin/ci/before_build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | $ctl = ENV["AMQP_GEM_RABBITMQCTL"] || ENV["RABBITMQCTL"] || "sudo rabbitmqctl" 4 | $plugins = ENV["AMQP_GEM_RABBITMQ_PLUGINS"] || ENV["RABBITMQ_PLUGINS"] || "sudo rabbitmq-plugins" 5 | 6 | def rabbit_control(args) 7 | command = "#{$ctl} #{args}" 8 | system command 9 | end 10 | 11 | def rabbit_plugins(args) 12 | command = "#{$plugins} #{args}" 13 | system command 14 | end 15 | 16 | # guest:guest has full access to / 17 | 18 | rabbit_control 'add_vhost /' 19 | rabbit_control 'add_user guest guest' 20 | rabbit_control 'set_permissions -p / guest ".*" ".*" ".*"' 21 | 22 | 23 | # amqp_gem:amqp_gem_password has full access to amqp_gem_testbed 24 | 25 | rabbit_control 'add_vhost amqp_gem_testbed' 26 | rabbit_control 'add_user amqp_gem amqp_gem_password' 27 | rabbit_control 'set_permissions -p amqp_gem_testbed amqp_gem ".*" ".*" ".*"' 28 | 29 | 30 | # amqp_gem_reader:reader_password has read access to amqp_gem_testbed 31 | 32 | rabbit_control 'add_user amqp_gem_reader reader_password' 33 | rabbit_control 'clear_permissions -p amqp_gem_testbed guest' 34 | rabbit_control 'set_permissions -p amqp_gem_testbed amqp_gem_reader "^---$" "^---$" ".*"' 35 | 36 | # requires RabbitMQ 3.0+ 37 | # $RABBITMQ_PLUGINS enable rabbitmq_consistent_hash_exchange 38 | 39 | # Reduce retention policy for faster publishing of stats 40 | rabbit_control "eval 'supervisor2:terminate_child(rabbit_mgmt_sup_sup, rabbit_mgmt_sup), application:set_env(rabbitmq_management, sample_retention_policies, [{global, [{605, 1}]}, {basic, [{605, 1}]}, {detailed, [{10, 1}]}]), rabbit_mgmt_sup_sup:start_child().'" 41 | rabbit_control "eval 'supervisor2:terminate_child(rabbit_mgmt_agent_sup_sup, rabbit_mgmt_agent_sup), application:set_env(rabbitmq_management_agent, sample_retention_policies, [{global, [{605, 1}]}, {basic, [{605, 1}]}, {detailed, [{10, 1}]}]), rabbit_mgmt_agent_sup_sup:start_child().'" 42 | -------------------------------------------------------------------------------- /bin/cleanify.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby -i 2 | # encoding: utf-8 3 | 4 | # Usage: 5 | # find . | egrep '\.rb$' | egrep -v cleanify.rb | xargs ./bin/cleanify.rb 6 | 7 | # \n at the end of the file 8 | # def foo a, b, &block 9 | # no trailing whitespace 10 | # encoding declaration 11 | 12 | ENCODING = "utf-8" 13 | 14 | while line = ARGF.gets 15 | # whitespace 16 | # line.chomp! 17 | line.gsub!(/\t/, " ") 18 | line.rstrip! 19 | 20 | # encoding 21 | if line.length == (ARGF.pos - 1) && ! line.match(/^#.*coding/) 22 | puts "# encoding: #{ENCODING}\n\n" 23 | end 24 | 25 | # def 26 | regexp = /^(\s*def \w[\w\d]*)\s+(.+)$/ 27 | if line.match(regexp) 28 | line.gsub!(regexp, '\1(\2)') 29 | end 30 | 31 | # foo{} => foo {} 32 | line.gsub!(/([^%][^#( ])(\{)/, '\1 \2') 33 | 34 | # a=foo => a = foo 35 | line.gsub!(/([^ ])(\+=)/, '\1 \2') 36 | line.gsub!(/(\+=)([^ ])/, '\1 \2') 37 | line.gsub!(/([^ :])(<<)/, '\1 \2') 38 | line.gsub!(/(<<)([^ ])/, '\1 \2') 39 | 40 | # foo=>bar 41 | line.gsub!(/([^\s])=>/, '\1 =>') 42 | line.gsub!(/=>([^\s])/, '=> \1') 43 | 44 | line.gsub!(/\{\|/, '{ |') 45 | 46 | line.gsub!(/,\s*/, ', ') 47 | line.rstrip! 48 | 49 | puts line 50 | end 51 | -------------------------------------------------------------------------------- /bin/docup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | yard server --reload 4 | -------------------------------------------------------------------------------- /bin/irb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | $LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__)) 5 | 6 | require "irb" 7 | require "amqp" 8 | 9 | IRB.start(__FILE__) 10 | -------------------------------------------------------------------------------- /bin/set_test_suite_realms_up.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # guest:guest has full access to / 4 | 5 | rabbitmqctl add_vhost / 6 | rabbitmqctl add_user guest guest 7 | rabbitmqctl set_permissions -p / guest ".*" ".*" ".*" 8 | 9 | 10 | # amqp_gem:amqp_gem_password has full access to amqp_gem_testbed 11 | 12 | rabbitmqctl add_vhost amqp_gem_testbed 13 | rabbitmqctl add_user amqp_gem amqp_gem_password 14 | rabbitmqctl set_permissions -p amqp_gem_testbed amqp_gem ".*" ".*" ".*" 15 | 16 | 17 | # amqp_gem_reader:reader_password has read access to amqp_gem_testbed 18 | 19 | rabbitmqctl add_user amqp_gem_reader reader_password 20 | rabbitmqctl clear_permissions -p amqp_gem_testbed guest 21 | rabbitmqctl set_permissions -p amqp_gem_testbed amqp_gem_reader "^---$" "^---$" ".*" -------------------------------------------------------------------------------- /docs/Clustering.textile: -------------------------------------------------------------------------------- 1 | # @title Ruby AMQP gem: Clustering 2 | 3 | h1. Clustering 4 | 5 | h2. This Documentation Has Moved to rubyamqp.info 6 | 7 | amqp gem documentation guides are now hosted on "rubyamqp.info":http://rubyamqp.info. 8 | 9 | 10 | h2. About this guide 11 | 12 | This guide covers clustered AMQP broker setups, with RabbitMQ as example. 13 | 14 | 15 | h2. Covered versions 16 | 17 | This guide covers "Ruby amqp gem":http://github.com/ruby-amqp/amqp v0.9.0 and later. 18 | 19 | TBD 20 | 21 | 22 | h2. Clustering 23 | 24 | TBD 25 | 26 | 27 | h2. Tell us what you think! 28 | 29 | 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: 30 | what was unclear? what wasn't covered? maybe you don't like guide style or grammar and spelling are incorrect? Readers feedback is 31 | key to making documentation better. 32 | 33 | 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 34 | -------------------------------------------------------------------------------- /docs/diagrams/001_hello_world_example_routing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/001_hello_world_example_routing.png -------------------------------------------------------------------------------- /docs/diagrams/002_blabbr_example_routing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/002_blabbr_example_routing.png -------------------------------------------------------------------------------- /docs/diagrams/003_weathr_example_routing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/003_weathr_example_routing.png -------------------------------------------------------------------------------- /docs/diagrams/004_fanout_exchange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/004_fanout_exchange.png -------------------------------------------------------------------------------- /docs/diagrams/005_direct_exchange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/005_direct_exchange.png -------------------------------------------------------------------------------- /docs/diagrams/006_amqp_091_message_acknowledgements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/006_amqp_091_message_acknowledgements.png -------------------------------------------------------------------------------- /docs/diagrams/007_rabbitmq_publisher_confirms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/007_rabbitmq_publisher_confirms.png -------------------------------------------------------------------------------- /docs/diagrams/redhat/direct_exchange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/redhat/direct_exchange.png -------------------------------------------------------------------------------- /docs/diagrams/redhat/fanout_exchange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/redhat/fanout_exchange.png -------------------------------------------------------------------------------- /docs/diagrams/redhat/topic_exchange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/docs/diagrams/redhat/topic_exchange.png -------------------------------------------------------------------------------- /examples/channels/open_channel_with_one_arity_callback.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Channel#initialize example that uses a block" 13 | puts 14 | AMQP.start(:host => 'localhost') do |connection| 15 | AMQP::Channel.new do |channel| 16 | puts "Channel ##{channel.id} is now open!" 17 | end 18 | 19 | 20 | show_stopper = Proc.new do 21 | $stdout.puts "Stopping..." 22 | 23 | connection.close { 24 | EM.stop { exit } 25 | } 26 | end 27 | 28 | Signal.trap "INT", show_stopper 29 | EM.add_timer(2, show_stopper) 30 | end 31 | -------------------------------------------------------------------------------- /examples/channels/open_channel_without_assignment.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Channel#initialize example that uses a block" 13 | puts 14 | AMQP.start(:host => 'localhost') do |connection| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" 17 | end 18 | 19 | 20 | show_stopper = Proc.new do 21 | $stdout.puts "Stopping..." 22 | 23 | connection.close { 24 | EM.stop { exit } 25 | } 26 | end 27 | 28 | Signal.trap "INT", show_stopper 29 | EM.add_timer(2, show_stopper) 30 | end 31 | -------------------------------------------------------------------------------- /examples/channels/prefetch_as_constructor_argument.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Channel#prefetch" 13 | puts 14 | AMQP.start(:host => 'localhost') do |connection| 15 | ch = AMQP::Channel.new(connection, AMQP::Channel.next_channel_id, :prefetch => 1) 16 | ch.on_error do |ex| 17 | raise "Oops! there has been a channel-level exception" 18 | end 19 | 20 | 21 | show_stopper = Proc.new do 22 | $stdout.puts "Stopping..." 23 | 24 | connection.close { 25 | EM.stop { exit } 26 | } 27 | end 28 | 29 | Signal.trap "INT", show_stopper 30 | EM.add_timer(1, show_stopper) 31 | end 32 | -------------------------------------------------------------------------------- /examples/channels/qos_aka_prefetch.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Channel#prefetch" 13 | puts 14 | AMQP.start(:host => 'localhost') do |connection| 15 | ch = AMQP::Channel.new 16 | ch.on_error do |ch, channel_close| 17 | raise "Oops! a channel-level exception: #{channel_close.inspect}" 18 | end 19 | ch.prefetch(1, false) do |_| 20 | puts "qos callback has fired" 21 | end 22 | 23 | 24 | show_stopper = Proc.new do 25 | $stdout.puts "Stopping..." 26 | 27 | connection.close { 28 | EM.stop { exit } 29 | } 30 | end 31 | 32 | Signal.trap "INT", &show_stopper 33 | EM.add_timer(1, show_stopper) 34 | end 35 | -------------------------------------------------------------------------------- /examples/channels/qos_aka_prefetch_without_callback.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Channel#prefetch" 13 | puts 14 | AMQP.start(:host => 'localhost') do |connection| 15 | ch = AMQP::Channel.new 16 | ch.on_error do |ch, channel_close| 17 | raise "Oops! a channel-level exception: #{channel_close.inspect}" 18 | end 19 | ch.prefetch(1, false) 20 | 21 | 22 | show_stopper = Proc.new do 23 | $stdout.puts "Stopping..." 24 | 25 | connection.close { 26 | EM.stop { exit } 27 | } 28 | end 29 | 30 | Signal.trap "INT", show_stopper 31 | EM.add_timer(1, show_stopper) 32 | end 33 | -------------------------------------------------------------------------------- /examples/connection/connect_and_immediately_disconnect.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | connection = AMQP.connect(:host => '127.0.0.1') 13 | connection.disconnect { 14 | EventMachine.stop 15 | } 16 | end 17 | -------------------------------------------------------------------------------- /examples/error_handling/automatic_recovery_of_channel_and_queues.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Example of automatic AMQP channel and queues recovery" 13 | puts 14 | AMQP.start(:host => "localhost") do |connection, open_ok| 15 | connection.on_error do |ch, connection_close| 16 | raise connection_close.reply_text 17 | end 18 | 19 | ch1 = AMQP::Channel.new(connection, 2, :auto_recovery => true) 20 | ch1.on_error do |ch, channel_close| 21 | raise channel_close.reply_text 22 | end 23 | 24 | if ch1.auto_recovering? 25 | puts "Channel #{ch1.id} IS auto-recovering" 26 | end 27 | 28 | connection.on_tcp_connection_loss do |conn, settings| 29 | puts "[network failure] Trying to reconnect..." 30 | conn.reconnect(false, 2) 31 | end 32 | 33 | 34 | ch1.queue("amqpgem.examples.queue1", :auto_delete => true).bind("amq.fanout") 35 | ch1.queue("amqpgem.examples.queue2", :auto_delete => true).bind("amq.fanout") 36 | ch1.queue("amqpgem.examples.queue3", :auto_delete => true).bind("amq.fanout").subscribe do |metadata, payload| 37 | end 38 | 39 | 40 | show_stopper = Proc.new { 41 | connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } 42 | } 43 | 44 | Signal.trap "TERM", show_stopper 45 | Signal.trap "INT", show_stopper 46 | EM.add_timer(30, show_stopper) 47 | 48 | 49 | puts "Connected, authenticated. To really exercise this example, shut RabbitMQ down for a few seconds. If you don't it will exit gracefully in 30 seconds." 50 | end 51 | -------------------------------------------------------------------------------- /examples/error_handling/automatically_recovering_hello_world_consumer.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Example of automatic AMQP channel and queues recovery" 12 | puts 13 | AMQP.start(:host => ENV.fetch("BROKER_HOST", "localhost")) do |connection, open_ok| 14 | connection.on_error do |ch, connection_close| 15 | puts "[connection closed] #{connection_close.reply_text}" 16 | end 17 | 18 | ch1 = AMQP::Channel.new(connection, :auto_recovery => true) 19 | ch1.on_error do |ch, channel_close| 20 | raise channel_close.reply_text 21 | end 22 | 23 | connection.on_tcp_connection_loss do |conn, settings| 24 | puts "[network failure] Trying to reconnect..." 25 | conn.reconnect(false, 2) 26 | end 27 | 28 | queue = ch1.queue("amqpgem.examples.autorecovery.queue", :auto_delete => false, :durable => true).bind("amq.fanout") 29 | queue.subscribe(:ack => true) do |metadata, payload| 30 | puts "[consumer1] => #{payload}" 31 | metadata.ack 32 | end 33 | consumer2 = AMQP::Consumer.new(ch1, queue) 34 | consumer2.consume.on_delivery do |metadata, payload| 35 | puts "[conusmer2] => #{payload}" 36 | metadata.ack 37 | end 38 | 39 | 40 | show_stopper = Proc.new { 41 | connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } 42 | } 43 | 44 | Signal.trap "TERM", show_stopper 45 | Signal.trap "INT", show_stopper 46 | EM.add_timer(ENV.fetch("TIMER", 45), show_stopper) 47 | 48 | 49 | puts "This example needs another script/app to publish messages to amq.fanout. See examples/error_handling/hello_world_producer.rb for example" 50 | puts "Connected, authenticated. To really exercise this example, shut RabbitMQ down for a few seconds. If you don't it will exit gracefully in 45 seconds." 51 | end 52 | -------------------------------------------------------------------------------- /examples/error_handling/automatically_recovering_hello_world_consumer_that_uses_a_server_named_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Example of automatic AMQP channel and queues recovery" 12 | puts 13 | AMQP.start(:host => "localhost") do |connection, open_ok| 14 | connection.on_error do |ch, connection_close| 15 | puts "[connection closed] #{connection_close.reply_text}" 16 | end 17 | 18 | ch1 = AMQP::Channel.new(connection, 2, :auto_recovery => true) 19 | ch1.on_error do |ch, channel_close| 20 | raise channel_close.reply_text 21 | end 22 | 23 | connection.on_tcp_connection_loss do |conn, settings| 24 | puts "[network failure] Trying to reconnect..." 25 | conn.reconnect(false, 2) 26 | end 27 | 28 | queue = ch1.queue("", :auto_delete => true, :exclusive => true).bind("amq.fanout") 29 | queue.subscribe(:ack => true) do |metadata, payload| 30 | puts "[consumer1] => #{payload}" 31 | metadata.ack 32 | end 33 | consumer2 = AMQP::Consumer.new(ch1, queue) 34 | consumer2.consume.on_delivery do |metadata, payload| 35 | puts "[conusmer2] => #{payload}" 36 | metadata.ack 37 | end 38 | 39 | 40 | show_stopper = Proc.new { 41 | connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } 42 | } 43 | 44 | Signal.trap "TERM", show_stopper 45 | Signal.trap "INT", show_stopper 46 | EM.add_timer(45, show_stopper) 47 | 48 | 49 | puts "This example needs another script/app to publish messages to amq.fanout. See examples/error_handling/hello_world_producer.rb for example" 50 | puts "Connected, authenticated. To really exercise this example, shut RabbitMQ down for a few seconds. If you don't it will exit gracefully in 45 seconds." 51 | end 52 | -------------------------------------------------------------------------------- /examples/error_handling/basic_connection_failover.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Example of basic failover with AMQP::Session#reconnect_to" 12 | puts 13 | AMQP.start(:host => "localhost") do |connection, open_ok| 14 | connection.on_recovery do |conn, settings| 15 | puts "Connection recovered, now connected to dev.rabbitmq.com" 16 | end 17 | 18 | connection.on_tcp_connection_loss do |conn, settings| 19 | puts "Trying to reconnect..." 20 | conn.reconnect_to("amqp://dev.rabbitmq.com") 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /examples/error_handling/channel_level_exception.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue redeclaration with different attributes results in a channel exception that is handled" 13 | puts 14 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" 17 | 18 | channel.on_error do |ch, channel_close| 19 | puts <<-ERR 20 | Handling a channel-level exception. 21 | 22 | AMQP class id : #{channel_close.class_id}, 23 | AMQP method id: #{channel_close.method_id}, 24 | Status code : #{channel_close.reply_code} 25 | Error message : #{channel_close.reply_text} 26 | ERR 27 | end 28 | 29 | EventMachine.add_timer(0.4) do 30 | # these two definitions result in a race condition. For sake of this example, 31 | # however, it does not matter. Whatever definition succeeds first, 2nd one will 32 | # cause a channel-level exception (because attributes are not identical) 33 | AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => false) do |queue| 34 | puts "#{queue.name} is ready to go" 35 | end 36 | 37 | AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => true) do |queue| 38 | puts "#{queue.name} is ready to go" 39 | end 40 | end 41 | end 42 | 43 | 44 | show_stopper = Proc.new do 45 | $stdout.puts "Stopping..." 46 | 47 | connection.close { 48 | EM.stop { exit } 49 | } 50 | end 51 | 52 | Signal.trap "INT", show_stopper 53 | EM.add_timer(2, show_stopper) 54 | end 55 | -------------------------------------------------------------------------------- /examples/error_handling/channel_level_exception_with_multiple_channels_involved.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue redeclaration with different attributes results in a channel exception that is handled" 13 | puts 14 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 15 | ch1 = AMQP::Channel.new(connection) do |ch, open_ok| 16 | puts "Channel ##{ch.id} is now open!" 17 | end 18 | ch1.on_error do |ch, close| 19 | raise "Handling channel-level exception on channel with id of #{ch.id} (ch1)" 20 | end 21 | 22 | ch2 = AMQP::Channel.new(connection) do |ch, open_ok| 23 | puts "Channel ##{ch.id} is now open!" 24 | end 25 | ch2.on_error do |ch, close| 26 | puts "close: #{close.inspect}" 27 | puts "Handling channel-level exception on channel with id of #{ch.id} (ch2)" 28 | end 29 | 30 | 31 | EventMachine.add_timer(0.2) do 32 | AMQP::Queue.new(ch1, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => false) do |queue| 33 | puts "#{queue.name} is ready to go" 34 | end 35 | end 36 | 37 | EventMachine.add_timer(0.6) do 38 | AMQP::Queue.new(ch2, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => true) do |queue| 39 | puts "#{queue.name} is ready to go" 40 | end 41 | end 42 | 43 | 44 | 45 | show_stopper = Proc.new do 46 | $stdout.puts "Stopping..." 47 | 48 | connection.close { 49 | EM.stop { exit } 50 | } 51 | end 52 | 53 | Signal.trap "INT", show_stopper 54 | EM.add_timer(2, show_stopper) 55 | end 56 | -------------------------------------------------------------------------------- /examples/error_handling/connection_level_exception.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | AMQP.connect(:host => '127.0.0.1', :port => 5672) do |connection| 13 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 14 | 15 | 16 | connection.on_error do |conn, connection_close| 17 | puts <<-ERR 18 | Handling a connection-level exception. 19 | 20 | AMQP class id : #{connection_close.class_id}, 21 | AMQP method id: #{connection_close.method_id}, 22 | Status code : #{connection_close.reply_code} 23 | Error message : #{connection_close.reply_text} 24 | ERR 25 | 26 | EventMachine.stop 27 | end 28 | 29 | # send_frame is NOT part of the public API, but it is public for entities like AMQ::Client::Channel 30 | # and we use it here to trigger a connection-level exception. MK. 31 | connection.send_frame(AMQ::Protocol::Connection::TuneOk.encode(1000, 1024 * 128 * 1024, 10)) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /examples/error_handling/connection_level_exception_with_objects.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | class ConnectionManager 13 | 14 | # 15 | # API 16 | # 17 | 18 | def connect(*args, &block) 19 | @connection = AMQP.connect(*args, &block) 20 | 21 | # combines Object#method and Method#to_proc to use object 22 | # method as a callback 23 | @connection.on_error(&method(:on_error)) 24 | end # connect(*args, &block) 25 | 26 | 27 | def on_error(connection, connection_close) 28 | puts "Handling a connection-level exception." 29 | puts 30 | puts "AMQP class id : #{connection_close.class_id}" 31 | puts "AMQP method id: #{connection_close.method_id}" 32 | puts "Status code : #{connection_close.reply_code}" 33 | puts "Error message : #{connection_close.reply_text}" 34 | end # on_error(connection, connection_close) 35 | end 36 | 37 | EventMachine.run do 38 | manager = ConnectionManager.new 39 | manager.connect(:host => '127.0.0.1', :port => 5672) do |connection| 40 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 41 | 42 | # send_frame is NOT part of the public API, but it is public for entities like AMQ::Client::Channel 43 | # and we use it here to trigger a connection-level exception. MK. 44 | connection.send_frame(AMQ::Protocol::Connection::TuneOk.encode(1000, 1024 * 128 * 1024, 10)) 45 | end 46 | 47 | # shut down after 2 seconds 48 | EventMachine.add_timer(2) { EventMachine.stop } 49 | end 50 | -------------------------------------------------------------------------------- /examples/error_handling/connection_loss_handler.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Connection loss is detected and handled" 13 | puts 14 | AMQP.start(:port => 5672, 15 | :vhost => "amq_client_testbed", 16 | :user => "amq_client_gem", 17 | :password => "amq_client_gem_password", 18 | :timeout => 0.3, 19 | :heartbeat => 1.0, 20 | :on_tcp_connection_failure => Proc.new { |settings| puts "Failed to connect, this was NOT expected"; EM.stop }) do |connection, open_ok| 21 | connection.on_tcp_connection_loss do |cl, settings| 22 | puts "tcp_connection_loss handler kicks in" 23 | cl.reconnect(false, 1) 24 | end 25 | 26 | 27 | show_stopper = Proc.new do 28 | $stdout.puts "Stopping..." 29 | connection.close { EventMachine.stop } 30 | end 31 | 32 | puts "Connected, authenticated. To really exercise this example, shut RabbitMQ down for a few seconds. If you don't it will exit gracefully in 30 seconds." 33 | 34 | Signal.trap "INT", show_stopper 35 | EM.add_timer(60, show_stopper) 36 | end 37 | -------------------------------------------------------------------------------- /examples/error_handling/global_channel_level_exception_handler.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue redeclaration with different attributes results in a channel exception that is handled by a global callback we carry from 0.7.x days" 13 | puts 14 | 15 | puts <<-MSG 16 | WARNING!! ACHTUNG!! AVIS!! AVISO!! Poorly designed API use ahead!! 17 | 18 | Please never ever use global error handler demonstrated below! 19 | It is a brilliant decision from early days of the library and we have to carry it 20 | along for backwards compatibility. 21 | 22 | Global state is programming is usually a pain. Global error handling is a 23 | true Hell. 24 | 25 | You have been warned. 26 | MSG 27 | 28 | puts 29 | puts 30 | 31 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 32 | AMQP::Channel.new do |channel, open_ok| 33 | puts "Channel ##{channel.id} is now open!" 34 | 35 | channel.on_error do |ch, channel_close| 36 | puts "Handling channel-level exception at instance level" 37 | end 38 | 39 | AMQP::Channel.on_error do |ch, channel_close| 40 | puts "Handling channel-level exception at GLOBAL level. Jeez. Message is #{channel_close.reply_text}" 41 | end 42 | 43 | EventMachine.add_timer(0.4) do 44 | q1 = AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => false) do |queue| 45 | puts "#{queue.name} is ready to go" 46 | end 47 | 48 | q2 = AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => true) do |queue| 49 | puts "#{queue.name} is ready to go" 50 | end 51 | end 52 | end 53 | 54 | 55 | show_stopper = Proc.new do 56 | $stdout.puts "Stopping..." 57 | 58 | connection.close { 59 | EM.stop { exit } 60 | } 61 | end 62 | 63 | Signal.trap "INT", show_stopper 64 | EM.add_timer(2, show_stopper) 65 | end 66 | -------------------------------------------------------------------------------- /examples/error_handling/handling_authentication_failure_with_a_callback.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Authentication failure handling with a callback" 13 | puts 14 | 15 | handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop } 16 | connection_settings = { 17 | :port => 5672, 18 | :vhost => "/amq_client_testbed", 19 | :user => "amq_client_gem", 20 | :password => "amq_client_gem_password_that_is_incorrect #{Time.now.to_i}", 21 | :timeout => 0.3, 22 | :on_tcp_connection_failure => handler, 23 | :on_possible_authentication_failure => Proc.new { |settings| 24 | puts "Authentication failed, as expected, settings are: #{settings.inspect}" 25 | 26 | EM.stop 27 | } 28 | } 29 | 30 | 31 | AMQP.start(connection_settings) do |connection, open_ok| 32 | raise "This should not be reachable" 33 | end 34 | -------------------------------------------------------------------------------- /examples/error_handling/handling_authentication_failure_with_a_rescue_block.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Authentication failure handling with a rescue block" 13 | puts 14 | 15 | handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop } 16 | connection_settings = { 17 | :port => 5672, 18 | :vhost => "/amq_client_testbed", 19 | :user => "amq_client_gem", 20 | :password => "amq_client_gem_password_that_is_incorrect #{Time.now.to_i}", 21 | :timeout => 0.3, 22 | :on_tcp_connection_failure => handler 23 | } 24 | 25 | 26 | begin 27 | AMQP.start(connection_settings) do |connection, open_ok| 28 | raise "This should not be reachable" 29 | end 30 | rescue AMQP::PossibleAuthenticationFailureError => afe 31 | puts "Authentication failed, as expected, caught #{afe.inspect}" 32 | EventMachine.stop if EventMachine.reactor_running? 33 | end 34 | -------------------------------------------------------------------------------- /examples/error_handling/handling_vhost_misconfiguration_with_a_rescue_block.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Authentication failure/vhost misconfiguration handling with a rescue block" 13 | puts 14 | 15 | handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop } 16 | connection_settings = { 17 | :port => 5672, 18 | :vhost => "/a/b/c/d/#{rand}/#{Time.now.to_i}", 19 | :user => "amq_client_gem", 20 | :password => "amq_client_gem_password_that_is_incorrect #{Time.now.to_i}", 21 | :timeout => 0.3, 22 | :on_tcp_connection_failure => handler 23 | } 24 | 25 | 26 | begin 27 | AMQP.start(connection_settings) do |connection, open_ok| 28 | raise "This should not be reachable" 29 | end 30 | rescue AMQP::PossibleAuthenticationFailureError => afe 31 | puts "Authentication failed, as expected, caught #{afe.inspect}" 32 | EventMachine.stop if EventMachine.reactor_running? 33 | end 34 | -------------------------------------------------------------------------------- /examples/error_handling/hello_world_producer.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Auxiliary script that tests automatically recovering message consumer(s)" 13 | puts 14 | AMQP.start(:host => ENV.fetch("BROKER_HOST", "localhost")) do |connection, open_ok| 15 | puts "Connected to #{connection.hostname}" 16 | connection.on_error do |ch, connection_close| 17 | raise connection_close.reply_text 18 | end 19 | 20 | connection.on_tcp_connection_loss do |conn, settings| 21 | puts "[network failure] Trying to reconnect..." 22 | conn.reconnect(false, 2) 23 | end 24 | 25 | 26 | ch1 = AMQP::Channel.new(connection, :auto_recovery => true) 27 | ch1.on_error do |ch, channel_close| 28 | raise channel_close.reply_text 29 | end 30 | 31 | 32 | exchange = ch1.fanout("amq.fanout", :durable => true) 33 | EventMachine.add_periodic_timer(0.9) do 34 | puts "Publishing via default exchange..." 35 | # messages must be routable & there must be at least one consumer. 36 | ch1.default_exchange.publish("Routed via default_exchange", :routing_key => "amqpgem.examples.autorecovery.queue") 37 | end 38 | 39 | EventMachine.add_periodic_timer(0.8) do 40 | puts "Publishing via amq.fanout..." 41 | # messages must be routable & there must be at least one consumer. 42 | exchange.publish("Routed via amq.fanout", :mandatory => true) 43 | end 44 | 45 | 46 | show_stopper = Proc.new { 47 | connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } 48 | } 49 | 50 | Signal.trap "TERM", show_stopper 51 | Signal.trap "INT", show_stopper 52 | EM.add_timer(ENV.fetch("TIMER", 15), show_stopper) 53 | 54 | puts "This example a helper that publishes messages to amq.fanout. Use together with examples/error_handling/automatically_recovering_hello_world_consumer.rb." 55 | puts "This example terminates in 15 seconds and needs MANUAL RESTART when connection fails" 56 | end 57 | -------------------------------------------------------------------------------- /examples/error_handling/insufficient_permissions.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue redeclaration with different attributes results in a channel exception that is handled" 13 | puts 14 | AMQP.start(:vhost => "amqp_gem_testbed", :username => "amqp_gem_reader", :password => "reader_password") do |connection, open_ok| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" 17 | 18 | channel.on_error do |ch, channel_close| 19 | puts <<-ERR 20 | Handling a channel-level exception. 21 | 22 | AMQP class id : #{channel_close.class_id}, 23 | AMQP method id: #{channel_close.method_id}, 24 | Status code : #{channel_close.reply_code} 25 | Error message : #{channel_close.reply_text} 26 | ERR 27 | end 28 | 29 | EventMachine.add_timer(0.4) do 30 | # these two definitions result in a race condition. For sake of this example, 31 | # however, it does not matter. Whatever definition succeeds first, 2nd one will 32 | # cause a channel-level exception (because attributes are not identical) 33 | AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => false) do |queue| 34 | puts "#{queue.name} is ready to go" 35 | end 36 | 37 | AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => true) do |queue| 38 | puts "#{queue.name} is ready to go" 39 | end 40 | end 41 | end 42 | 43 | 44 | show_stopper = Proc.new do 45 | $stdout.puts "Stopping..." 46 | 47 | connection.close { 48 | EM.stop { exit } 49 | } 50 | end 51 | 52 | Signal.trap "INT", show_stopper 53 | EM.add_timer(2, show_stopper) 54 | end 55 | -------------------------------------------------------------------------------- /examples/error_handling/manual_connection_and_channel_recovery.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | class ConnectionInterruptionHandler 13 | 14 | # 15 | # API 16 | # 17 | 18 | def handle(connection) 19 | puts "[network failure] Connection #{connection} detected connection interruption" 20 | end 21 | 22 | end 23 | 24 | 25 | puts "=> Example of AMQP connection & channel recovery API in action" 26 | puts 27 | AMQP.start(:host => "localhost") do |connection, open_ok| 28 | unless connection.auto_recovering? 29 | puts "Connection IS NOT auto-recovering..." 30 | end 31 | 32 | ch1 = AMQP::Channel.new(connection) 33 | ch1.on_error do |ch, channel_close| 34 | raise channel_close.reply_text 35 | end 36 | 37 | unless ch1.auto_recovering? 38 | puts "Channel #{ch1.id} IS NOT auto-recovering" 39 | end 40 | ch1.on_connection_interruption do |c| 41 | puts "[network failure] Channel #{c.id} reacted to connection interruption" 42 | end 43 | ch1.on_recovery do |c| 44 | puts "[recovery] Channel #{c.id} has recovered" 45 | end 46 | 47 | 48 | connection.on_tcp_connection_loss do |conn, settings| 49 | puts "[network failure] Trying to reconnect..." 50 | conn.reconnect(false, 2) 51 | end 52 | 53 | 54 | handler = ConnectionInterruptionHandler.new 55 | connection.on_connection_interruption(&handler.method(:handle)) 56 | 57 | connection.on_recovery do |conn, settings| 58 | puts "[recovery] Connection has recovered" 59 | end 60 | 61 | show_stopper = Proc.new { 62 | connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } 63 | } 64 | 65 | Signal.trap "TERM", show_stopper 66 | Signal.trap "INT", show_stopper 67 | EM.add_timer(30, show_stopper) 68 | 69 | 70 | puts "Connected, authenticated. To really exercise this example, shut RabbitMQ down for a few seconds. If you don't it will exit gracefully in 30 seconds." 71 | end 72 | -------------------------------------------------------------------------------- /examples/error_handling/queue_exclusivity_violation.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue exclusivity violation results " 13 | puts 14 | EventMachine.run do 15 | connection1 = AMQP.connect("amqp://guest:guest@dev.rabbitmq.com") 16 | channel1 = AMQP::Channel.new(connection1) 17 | 18 | connection2 = AMQP.connect("amqp://guest:guest@dev.rabbitmq.com") 19 | channel2 = AMQP::Channel.new(connection2) 20 | 21 | channel1.on_error do |ch, close| 22 | puts "Handling a channel-level exception on channel1: #{close.reply_text}, #{close.reply_code}" 23 | end 24 | channel2.on_error do |ch, close| 25 | puts "Handling a channel-level exception on channel2: #{close.reply_text}, #{close.reply_code}" 26 | end 27 | 28 | name = "amqpgem.examples.queue" 29 | channel1.queue(name, :auto_delete => true, :exclusive => true) 30 | # declare a queue with the same name on a different connection 31 | channel2.queue(name, :auto_delete => true, :exclusive => true) 32 | 33 | 34 | EventMachine.add_timer(3.5) do 35 | connection1.close { 36 | connection2.close { 37 | EventMachine.stop { exit } 38 | } 39 | } 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /examples/error_handling/queue_name_violation.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue declaration uses name prefix amq.* reserved by the AMQP spec" 13 | puts 14 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" 17 | 18 | channel.on_error do |ch, close| 19 | puts "Handling a channel-level exception: #{close.reply_text}, code: #{close.reply_code}" 20 | end 21 | 22 | channel.queue("amq.queue") 23 | end 24 | 25 | 26 | EventMachine.add_timer(0.5) do 27 | connection.close { 28 | EventMachine.stop { exit } 29 | } 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /examples/error_handling/reopening_a_channel_after_channel_level_exception.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue redeclaration with different attributes results in a channel exception that is handled" 13 | puts 14 | EventMachine.run do 15 | connection = AMQP.connect(:port => ENV.fetch("PORT", 5672)) 16 | AMQP::Channel.new(connection) do |channel, open_ok| 17 | puts "Channel ##{channel.id} is now open!" 18 | 19 | connection.on_error do |conn, connection_close| 20 | puts <<-ERR 21 | Handling a connection-level exception: 22 | 23 | connection_close.reply_text: #{connection_close.reply_text} 24 | ERR 25 | end 26 | 27 | channel.on_error do |ch, channel_close| 28 | puts "Handling a channel-level exception: #{channel_close.reply_code} #{channel_close.reply_text}" 29 | ch.reuse 30 | end 31 | 32 | # initial operations that cause the channel-level exception handled above 33 | EventMachine.add_timer(0.5) do 34 | # these two definitions result in a race condition. For sake of this example, 35 | # however, it does not matter. Whatever definition succeeds first, 2nd one will 36 | # cause a channel-level exception (because attributes are not identical) 37 | AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :exclusive => true, :durable => false) 38 | AMQP::Queue.new(channel, "amqpgem.examples.channel_exception", :auto_delete => true, :durable => true) 39 | end 40 | 41 | EventMachine.add_timer(2.0) do 42 | puts "Resuming with reopened channel #{channel.id}" 43 | q = channel.queue("amqpgem.examples.channel_exception.q1", :exclusive => true).bind("amq.fanout").subscribe do |meta, payload| 44 | puts "Consumed #{payload}" 45 | end 46 | end 47 | 48 | EventMachine.add_periodic_timer(3.0) do 49 | puts "Publishing a message..." 50 | x = channel.fanout("amq.fanout") 51 | x.publish("xyz", :routing_key => "amqpgem.examples.channel_exception.q1") 52 | end 53 | end 54 | 55 | 56 | show_stopper = Proc.new do 57 | $stdout.puts "Stopping..." 58 | 59 | connection.close { 60 | EM.stop { exit } 61 | } 62 | end 63 | 64 | Signal.trap "INT", show_stopper 65 | # EM.add_timer(2, show_stopper) 66 | end 67 | -------------------------------------------------------------------------------- /examples/error_handling/tcp_connection_failure_handling_with_a_rescue_block.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> TCP connection failure handling with a rescue statement" 13 | puts 14 | 15 | connection_settings = { 16 | :port => 9689, 17 | :vhost => "/amq_client_testbed", 18 | :user => "amq_client_gem", 19 | :password => "amq_client_gem_password", 20 | :timeout => 0.3 21 | } 22 | 23 | begin 24 | AMQP.start(connection_settings) do |connection, open_ok| 25 | raise "This should not be reachable" 26 | end 27 | rescue AMQP::TCPConnectionFailed => e 28 | puts "Caught AMQP::TCPConnectionFailed => TCP connection failed, as expected." 29 | end 30 | 31 | -------------------------------------------------------------------------------- /examples/error_handling/tcp_connection_failure_with_a_callback.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> TCP connection failure handling with a callback" 13 | puts 14 | 15 | handler = Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop } 16 | connection_settings = { 17 | :port => 9689, 18 | :vhost => "/amq_client_testbed", 19 | :user => "amq_client_gem", 20 | :password => "amq_client_gem_password", 21 | :timeout => 0.3, 22 | :on_tcp_connection_failure => handler 23 | } 24 | 25 | 26 | AMQP.start(connection_settings) do |connection, open_ok| 27 | raise "This should not be reachable" 28 | end 29 | -------------------------------------------------------------------------------- /examples/exchanges/autodeletion_of_exchanges.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Exchange#initialize example that uses :auto_delete => true" 13 | puts 14 | AMQP.start(:host => 'localhost', :port => 5673) do |connection| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" 17 | 18 | AMQP::Exchange.new(channel, :direct, "amqpgem.examples.xchange2", :auto_delete => false) do |exchange| 19 | puts "#{exchange.name} is ready to go" 20 | end 21 | 22 | AMQP::Exchange.new(channel, :direct, "amqpgem.examples.xchange3", :auto_delete => true) do |exchange| 23 | puts "#{exchange.name} is ready to go" 24 | end 25 | end 26 | 27 | show_stopper = Proc.new do 28 | $stdout.puts "Stopping..." 29 | connection.close { EventMachine.stop } 30 | end 31 | 32 | Signal.trap "INT", show_stopper 33 | EM.add_timer(2, show_stopper) 34 | end 35 | -------------------------------------------------------------------------------- /examples/exchanges/declare_an_exchange_without_assignment.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Exchange#initialize example that uses a block" 13 | puts 14 | AMQP.start(:host => 'localhost') do |connection| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" 17 | 18 | AMQP::Exchange.new(channel, :direct, "amqpgem.examples.xchange1", :auto_delete => true) do |exchange| 19 | puts "#{exchange.name} is ready to go" 20 | end 21 | 22 | AMQP::Exchange.new(channel, :direct, "amqpgem.examples.xchange1", :auto_delete => true) do |exchange, declare_ok| 23 | puts "#{exchange.name} is ready to go. AMQP method: #{declare_ok.inspect}" 24 | end 25 | 26 | channel.direct("amqpgem.examples.xchange2", :auto_delete => true) do |exchange, declare_ok| 27 | puts "#{exchange.name} is ready to go. AMQP method: #{declare_ok.inspect}" 28 | end 29 | end 30 | 31 | 32 | show_stopper = Proc.new do 33 | $stdout.puts "Stopping..." 34 | 35 | connection.close { 36 | EM.stop { exit } 37 | } 38 | end 39 | 40 | Signal.trap "INT", show_stopper 41 | EM.add_timer(2, show_stopper) 42 | end 43 | -------------------------------------------------------------------------------- /examples/extensions/rabbitmq/connection_blocking.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../../lib", __FILE__)) 8 | require 'amqp' 9 | require "amqp/extensions/rabbitmq" 10 | 11 | puts "=> Demonstrating connection.blocked" 12 | puts 13 | 14 | # This example requires high memory watermark to be set 15 | # really low to demonstrate blocking. 16 | # 17 | # rabbitmqctl set_vm_memory_high_watermark 0.00000001 18 | # 19 | # should do it. 20 | 21 | EventMachine.run do 22 | connection = AMQP.connect(:host => '127.0.0.1') 23 | 24 | connection.on_blocked do |conn, conn_blocked| 25 | puts "Connection blocked, reason: #{conn_blocked.reason}" 26 | end 27 | 28 | connection.on_unblocked do |conn, _| 29 | puts "Connection unblocked" 30 | end 31 | 32 | puts "Connecting to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 33 | 34 | AMQP::Channel.new(connection) do |ch| 35 | x = ch.default_exchange 36 | 37 | puts "Publishing..." 38 | x.publish("z" * 1024 * 1024 * 24) 39 | end 40 | 41 | show_stopper = Proc.new { 42 | connection.close { EventMachine.stop } 43 | } 44 | 45 | EM.add_timer(120, show_stopper) 46 | Signal.trap('INT', show_stopper) 47 | Signal.trap('TERM', show_stopper) 48 | end 49 | -------------------------------------------------------------------------------- /examples/extensions/rabbitmq/per_queue_message_ttl.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../../lib", __FILE__)) 8 | require 'amqp' 9 | require "amqp/extensions/rabbitmq" 10 | 11 | AMQP.start do |connection| 12 | puts "Connected!" 13 | channel = AMQP::Channel.new(connection) 14 | channel.on_error do |ch, channel_close| 15 | puts "Oops! a channel-level exception: #{channel_close.reply_text}" 16 | end 17 | 18 | x = channel.fanout("amq.fanout") 19 | channel.queue("", :auto_delete => true, :arguments => { "x-message-ttl" => 1000 }) do |q| 20 | puts "Declared a new server-named queue: #{q.name}" 21 | q.bind(x) 22 | 23 | 24 | EventMachine.add_timer(0.3) do 25 | 10.times do |i| 26 | puts "Publishing message ##{i}" 27 | x.publish("Message ##{i}") 28 | end 29 | end 30 | 31 | EventMachine.add_timer(0.7) do 32 | q.pop do |headers, payload| 33 | puts "Got a message: #{payload}" 34 | end 35 | end 36 | 37 | EventMachine.add_timer(1.5) do 38 | q.pop do |headers, payload| 39 | if payload.nil? 40 | puts "No messages in the queue" 41 | else 42 | raise "x-message-ttl didn't seem to work (timeout isn't up)" 43 | end 44 | end 45 | end 46 | end 47 | 48 | show_stopper = Proc.new { 49 | AMQP.stop { EventMachine.stop } 50 | } 51 | 52 | 53 | EM.add_timer(3, show_stopper) 54 | Signal.trap('INT', show_stopper) 55 | Signal.trap('TERM', show_stopper) 56 | end 57 | -------------------------------------------------------------------------------- /examples/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../../lib", __FILE__)) 8 | require 'amqp' 9 | require "amqp/extensions/rabbitmq" 10 | 11 | EventMachine.run do 12 | connection = AMQP.connect(:host => '127.0.0.1') 13 | puts "Connecting to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 14 | 15 | AMQP::Channel.new(connection) do |channel| 16 | puts "Channel #{channel.id} is now open" 17 | 18 | channel.confirm_select 19 | channel.on_error { |ch, channel_close| puts "Oops! a channel-level exception: #{channel_close.reply_text}" } 20 | channel.on_ack { |basic_ack| puts "Received basic_ack: multiple = #{basic_ack.multiple}, delivery_tag = #{basic_ack.delivery_tag}" } 21 | 22 | x = channel.fanout("amq.fanout") 23 | channel.queue("", :auto_delete => true) do |q| 24 | q.bind(x).subscribe(:ack => true) do |header, payload| 25 | puts "Received #{payload}" 26 | end 27 | end 28 | 29 | EventMachine.add_timer(0.5) do 30 | 10.times do |i| 31 | puts "Publishing message ##{i + 1}" 32 | x.publish("Message ##{i + 1}") 33 | end 34 | end 35 | end 36 | 37 | show_stopper = Proc.new { 38 | connection.close { EventMachine.stop } 39 | } 40 | 41 | EM.add_timer(6, show_stopper) 42 | Signal.trap('INT', show_stopper) 43 | Signal.trap('TERM', show_stopper) 44 | end 45 | -------------------------------------------------------------------------------- /examples/extensions/rabbitmq/using_alternate_exchanges.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | connection = AMQP.connect(:host => '127.0.0.1') 13 | puts "Connecting to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 14 | 15 | channel = AMQP::Channel.new(connection) 16 | queue = channel.queue("amqpgem.examples.hello_world", :auto_delete => true) 17 | exchange1 = channel.fanout("my.fanout1", :auto_delete => true) 18 | exchange2 = channel.fanout("my.fanout2", :auto_delete => true, :arguments => { "alternate-exchange" => "my.fanout1" }) 19 | 20 | queue.bind(exchange1).subscribe do |payload| 21 | puts "Received a message: #{payload}. Disconnecting..." 22 | 23 | connection.close { EventMachine.stop } 24 | end 25 | 26 | exchange1.publish "This message will be routed because of the binding", :mandatory => true 27 | exchange2.publish "This message will be re-routed to alternate-exchange", :mandatory => true 28 | end 29 | -------------------------------------------------------------------------------- /examples/guides/getting_started/01_hello_world.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | EventMachine.run do 8 | connection = AMQP.connect(:host => '127.0.0.1') 9 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 10 | 11 | channel = AMQP::Channel.new(connection) 12 | queue = channel.queue("amqpgem.examples.helloworld", :auto_delete => true) 13 | exchange = channel.direct("") 14 | 15 | queue.subscribe do |payload| 16 | puts "Received a message: #{payload}. Disconnecting..." 17 | 18 | connection.close { 19 | EM.stop { exit } 20 | } 21 | end 22 | 23 | exchange.publish "Hello, world!", :routing_key => queue.name 24 | end 25 | -------------------------------------------------------------------------------- /examples/guides/getting_started/02_hello_world_dslified.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | EventMachine.run do 8 | AMQP.connect(:host => '127.0.0.1') do |connection| 9 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 10 | 11 | channel = AMQP::Channel.new(connection) 12 | 13 | channel.queue("amqpgem.examples.helloworld", :auto_delete => true).subscribe do |payload| 14 | puts "Received a message: #{payload}. Disconnecting..." 15 | 16 | connection.close { 17 | EM.stop { exit } 18 | } 19 | end 20 | 21 | channel.direct("").publish "Hello, world!", :routing_key => "amqpgem.examples.helloworld" 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /examples/guides/getting_started/03_blabbr.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | AMQP.start("amqp://dev.rabbitmq.com:5672") do |connection| 8 | channel = AMQP::Channel.new(connection) 9 | exchange = channel.fanout("nba.scores") 10 | 11 | channel.queue("joe", :auto_delete => true).bind(exchange).subscribe do |payload| 12 | puts "#{payload} => joe" 13 | end 14 | 15 | channel.queue("aaron", :auto_delete => true).bind(exchange).subscribe do |payload| 16 | puts "#{payload} => aaron" 17 | end 18 | 19 | channel.queue("bob", :auto_delete => true).bind(exchange).subscribe do |payload| 20 | puts "#{payload} => bob" 21 | end 22 | 23 | exchange.publish("BOS 101, NYK 89").publish("ORL 85, ALT 88") 24 | 25 | # disconnect & exit after 2 seconds 26 | EventMachine.add_timer(2) do 27 | exchange.delete 28 | 29 | connection.close { 30 | EM.stop { exit } 31 | } 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /examples/guides/queues/01a_declaring_a_server_named_queue_using_queue_constructor.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Declaring a queue with server-generated name using AMQP::Queue constructor 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | channel = AMQP::Channel.new(connection) 10 | AMQP::Queue.new(channel, "", :auto_delete => true) do |queue| 11 | puts "#{queue.name} is ready to go." 12 | 13 | connection.close { 14 | EventMachine.stop { exit } 15 | } 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /examples/guides/queues/01b_declaring_a_queue_using_queue_constructor.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Declaring a queue with explicitly given name using AMQP::Queue constructor 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | channel = AMQP::Channel.new(connection) 10 | queue = AMQP::Queue.new(channel, "images.resize", :auto_delete => true) 11 | 12 | puts "#{queue.name} is ready to go." 13 | 14 | connection.close { 15 | EventMachine.stop { exit } 16 | } 17 | end 18 | -------------------------------------------------------------------------------- /examples/guides/queues/02a_declaring_a_durable_shared_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Declaring a durable shared queue 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | channel = AMQP::Channel.new(connection) 10 | queue = AMQP::Queue.new(channel, "images.resize", :durable => true) 11 | 12 | connection.close { 13 | EventMachine.stop { exit } 14 | } 15 | end 16 | -------------------------------------------------------------------------------- /examples/guides/queues/02b_declaring_a_durable_shared_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Declaring a durable shared queue using AMQP::Channel#queue method 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | channel = AMQP::Channel.new(connection) 10 | queue = channel.queue("images.resize", :durable => true) 11 | 12 | connection.close { 13 | EventMachine.stop { exit } 14 | } 15 | end 16 | -------------------------------------------------------------------------------- /examples/guides/queues/03a_declaring_a_temporary_exclusive_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Declaring a temporary exclusive queue 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | channel = AMQP::Channel.new(connection) 10 | 11 | AMQP::Queue.new(channel, "", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 12 | puts "#{queue.name} is ready to go." 13 | 14 | connection.close { 15 | EventMachine.stop { exit } 16 | } 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /examples/guides/queues/03b_declaring_a_temporary_exclusive_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Declaring a temporary exclusive queue 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | AMQP::Channel.new do |channel, open_ok| 10 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 11 | puts "#{queue.name} is ready to go." 12 | 13 | connection.close { 14 | EventMachine.stop { exit } 15 | } 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /examples/guides/queues/04_bind_a_queue_using_exchange_instance.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Binding a queue to an exchange 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | channel = AMQP::Channel.new(connection) 10 | exchange = channel.fanout("amq.fanout") 11 | 12 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 13 | queue.bind(exchange) do |bind_ok| 14 | puts "Just bound #{queue.name} to #{exchange.name}" 15 | end 16 | 17 | connection.close { 18 | EventMachine.stop { exit } 19 | } 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /examples/guides/queues/05_bind_a_queue_using_exchange_name.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | # Binding a queue to an exchange 8 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 9 | channel = AMQP::Channel.new(connection) 10 | exchange_name = "amq.fanout" 11 | 12 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 13 | queue.bind(exchange_name) 14 | puts "Bound #{queue.name} to #{exchange_name}" 15 | 16 | connection.close { 17 | EventMachine.stop { exit } 18 | } 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /examples/guides/queues/06_subscribe_to_receive_messages.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 8 | channel = AMQP::Channel.new(connection) 9 | exchange = channel.fanout("amq.fanout") 10 | 11 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue| 12 | queue.bind(exchange).subscribe do |metadata, payload| 13 | puts "Received a message: #{payload.inspect}. Shutting down..." 14 | 15 | connection.close { EventMachine.stop } 16 | end 17 | 18 | EventMachine.add_timer(0.2) do 19 | puts "=> Publishing..." 20 | exchange.publish("Ohai!") 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /examples/guides/queues/07_fetch_a_message_from_the_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 8 | channel = AMQP::Channel.new(connection) 9 | exchange = channel.fanout("amq.fanout") 10 | 11 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 12 | queue.bind(exchange) 13 | puts "Bound. Publishing a message..." 14 | exchange.publish("Ohai!") 15 | 16 | EventMachine.add_timer(0.5) do 17 | queue.pop do |metadata, payload| 18 | if payload 19 | puts "Fetched a message: #{payload.inspect}, content_type: #{metadata.content_type}. Shutting down..." 20 | else 21 | puts "No messages in the queue" 22 | end 23 | 24 | connection.close { EventMachine.stop } 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /examples/guides/queues/08_unsubscribing_a_consumer.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 8 | channel = AMQP::Channel.new(connection) 9 | exchange = channel.fanout("amq.fanout") 10 | 11 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 12 | queue.bind(exchange).subscribe do |headers, payload| 13 | puts "Received a new message" 14 | end 15 | 16 | EventMachine.add_timer(0.3) do 17 | queue.unsubscribe 18 | puts "Unsubscribed. Shutting down..." 19 | 20 | connection.close { EventMachine.stop } 21 | end # EventMachine.add_timer 22 | end # channel.queue 23 | end 24 | -------------------------------------------------------------------------------- /examples/guides/queues/09_unbinding_from_exchange.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 8 | channel = AMQP::Channel.new(connection) 9 | channel.on_error do |ch, channel_close| 10 | raise "Channel-level exception: #{channel_close.reply_text}" 11 | end 12 | 13 | exchange = channel.fanout("amq.fanout") 14 | 15 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 16 | queue.bind(exchange) 17 | 18 | EventMachine.add_timer(0.5) do 19 | queue.unbind(exchange) do |_| 20 | puts "Unbound. Shutting down..." 21 | 22 | connection.close { EventMachine.stop } 23 | end 24 | end # EventMachine.add_timer 25 | end # channel.queue 26 | end 27 | -------------------------------------------------------------------------------- /examples/guides/queues/10_purge_a_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 8 | channel = AMQP::Channel.new(connection) 9 | channel.on_error do |ch, channel_close| 10 | raise "Channel-level exception: #{channel_close.reply_text}" 11 | end 12 | exchange = channel.fanout("amq.fanout") 13 | 14 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 15 | queue.purge do |_| 16 | puts "Purged #{queue.name}" 17 | end 18 | 19 | EventMachine.add_timer(0.5) do 20 | connection.close { EventMachine.stop } 21 | end # EventMachine.add_timer 22 | end # channel.queue 23 | end 24 | -------------------------------------------------------------------------------- /examples/guides/queues/11_deleting_a_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 8 | channel = AMQP::Channel.new(connection) 9 | channel.on_error do |ch, channel_close| 10 | raise "Channel-level exception: #{channel_close.reply_text}" 11 | end 12 | exchange = channel.fanout("amq.fanout") 13 | 14 | channel.queue("", :auto_delete => true, :exclusive => true) do |queue, declare_ok| 15 | EventMachine.add_timer(0.5) do 16 | queue.delete do 17 | puts "Deleted #{queue.name}" 18 | connection.close { EventMachine. stop } 19 | end 20 | end # EventMachine.add_timer 21 | end # channel.queue 22 | end 23 | -------------------------------------------------------------------------------- /examples/guides/queues/12_objects_that_consume_messages.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | class Consumer 8 | 9 | # 10 | # API 11 | # 12 | 13 | def initialize(channel, queue_name = AMQ::Protocol::EMPTY_STRING) 14 | @queue_name = queue_name 15 | 16 | @channel = channel 17 | @channel.on_error(&method(:handle_channel_exception)) 18 | end # initialize 19 | 20 | def start 21 | @queue = @channel.queue(@queue_name, :exclusive => true) 22 | @queue.subscribe(&method(:handle_message)) 23 | end # start 24 | 25 | 26 | 27 | # 28 | # Implementation 29 | # 30 | 31 | def handle_message(metadata, payload) 32 | puts "Received a message: #{payload}, content_type = #{metadata.content_type}" 33 | end # handle_message(metadata, payload) 34 | 35 | def handle_channel_exception(channel, channel_close) 36 | puts "Oops... a channel-level exception: code = #{channel_close.reply_code}, message = #{channel_close.reply_text}" 37 | end # handle_channel_exception(channel, channel_close) 38 | end 39 | 40 | 41 | class Producer 42 | 43 | # 44 | # API 45 | # 46 | 47 | def initialize(channel, exchange) 48 | @channel = channel 49 | @exchange = exchange 50 | end # initialize(channel, exchange) 51 | 52 | def publish(message, options = {}) 53 | @exchange.publish(message, options) 54 | end # publish(message, options = {}) 55 | end 56 | 57 | 58 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 59 | channel = AMQP::Channel.new(connection) 60 | worker = Consumer.new(channel, "amqpgem.objects.integration") 61 | worker.start 62 | 63 | producer = Producer.new(channel, channel.default_exchange) 64 | puts "Publishing..." 65 | producer.publish("Hello, world", :routing_key => "amqpgem.objects.integration") 66 | 67 | # stop in 2 seconds 68 | EventMachine.add_timer(2.0) { connection.close { EventMachine.stop } } 69 | end 70 | -------------------------------------------------------------------------------- /examples/guides/queues/13_objects_that_consume_messages_take_two.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require "amqp" 6 | 7 | class Consumer 8 | 9 | # 10 | # API 11 | # 12 | 13 | def handle_message(metadata, payload) 14 | puts "Received a message: #{payload}, content_type = #{metadata.content_type}" 15 | end # handle_message(metadata, payload) 16 | end 17 | 18 | 19 | class Worker 20 | 21 | # 22 | # API 23 | # 24 | 25 | 26 | def initialize(channel, queue_name = AMQ::Protocol::EMPTY_STRING, consumer = Consumer.new) 27 | @queue_name = queue_name 28 | 29 | @channel = channel 30 | @channel.on_error(&method(:handle_channel_exception)) 31 | 32 | @consumer = consumer 33 | end # initialize 34 | 35 | def start 36 | @queue = @channel.queue(@queue_name, :exclusive => true) 37 | @queue.subscribe(&@consumer.method(:handle_message)) 38 | end # start 39 | 40 | 41 | 42 | # 43 | # Implementation 44 | # 45 | 46 | def handle_channel_exception(channel, channel_close) 47 | puts "Oops... a channel-level exception: code = #{channel_close.reply_code}, message = #{channel_close.reply_text}" 48 | end # handle_channel_exception(channel, channel_close) 49 | end 50 | 51 | 52 | class Producer 53 | 54 | # 55 | # API 56 | # 57 | 58 | def initialize(channel, exchange) 59 | @channel = channel 60 | @exchange = exchange 61 | end # initialize(channel, exchange) 62 | 63 | def publish(message, options = {}) 64 | @exchange.publish(message, options) 65 | end # publish(message, options = {}) 66 | 67 | 68 | # 69 | # Implementation 70 | # 71 | 72 | def handle_channel_exception(channel, channel_close) 73 | puts "Oops... a channel-level exception: code = #{channel_close.reply_code}, message = #{channel_close.reply_text}" 74 | end # handle_channel_exception(channel, channel_close) 75 | end 76 | 77 | 78 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com") do |connection, open_ok| 79 | channel = AMQP::Channel.new(connection) 80 | worker = Worker.new(channel, "amqpgem.objects.integration") 81 | worker.start 82 | 83 | producer = Producer.new(channel, channel.default_exchange) 84 | puts "Publishing..." 85 | producer.publish("Hello, world", :routing_key => "amqpgem.objects.integration") 86 | 87 | # stop in 2 seconds 88 | EventMachine.add_timer(2.0) { connection.close { EventMachine.stop } } 89 | end 90 | -------------------------------------------------------------------------------- /examples/hello_world.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | connection = AMQP.connect(:host => '127.0.0.1') 13 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 14 | 15 | channel = AMQP::Channel.new(connection) 16 | queue = channel.queue("amqpgem.examples.hello_world", :auto_delete => true) 17 | exchange = channel.default_exchange 18 | 19 | queue.subscribe do |payload| 20 | puts "Received a message: #{payload}. Disconnecting..." 21 | 22 | connection.close { EventMachine.stop } 23 | end 24 | 25 | exchange.publish "Hello, world!", :routing_key => queue.name, :app_id => "Hello world" 26 | end 27 | -------------------------------------------------------------------------------- /examples/hello_world_with_an_empty_string.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | connection = AMQP.connect(:host => '127.0.0.1') 13 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 14 | 15 | 16 | connection.on_error do |conn, connection_close| 17 | puts "Handling a connection-level exception: #{connection_close.reply_text}" 18 | EventMachine.stop 19 | end 20 | 21 | channel = AMQP::Channel.new(connection) 22 | queue = channel.queue("amqpgem.examples.hello_world", :auto_delete => true) 23 | exchange = channel.direct("") 24 | 25 | queue.subscribe do |payload| 26 | puts "Received a message: #{payload}. Disconnecting..." 27 | 28 | connection.close { EventMachine.stop } 29 | end 30 | 31 | exchange.publish "", :routing_key => queue.name, :app_id => "Hello world" 32 | end 33 | -------------------------------------------------------------------------------- /examples/hello_world_with_eventmachine_in_a_separate_thread.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | t = Thread.new { EventMachine.run } 12 | if defined?(JRUBY_VERSION) 13 | # on the JVM, event loop startup takes longer and .next_tick behavior 14 | # seem to be a bit different. Blocking current thread for a moment helps. 15 | sleep 0.5 16 | end 17 | 18 | EventMachine.next_tick { 19 | connection = AMQP.connect(:host => '127.0.0.1') 20 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 21 | 22 | channel = AMQP::Channel.new(connection) 23 | queue = channel.queue("amqpgem.examples.hello_world", :auto_delete => true) 24 | exchange = channel.direct("") 25 | 26 | queue.subscribe do |payload| 27 | puts "Received a message: #{payload}. Disconnecting..." 28 | 29 | connection.close { 30 | EM.stop { exit } 31 | } 32 | end 33 | 34 | exchange.publish "Hello, world!", :routing_key => queue.name 35 | } 36 | 37 | t.join 38 | -------------------------------------------------------------------------------- /examples/inspecting_server_information.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | AMQP.connect(:host => '127.0.0.1') do |connection| 13 | puts 14 | puts "Connected to #{connection.hostname}:#{connection.port}/#{connection.vhost}" 15 | puts 16 | puts "Client properties:" 17 | puts 18 | puts connection.client_properties.inspect 19 | 20 | puts "Server properties:" 21 | puts 22 | puts connection.server_properties.inspect 23 | 24 | puts "Server capabilities:" 25 | puts 26 | puts connection.server_capabilities.inspect 27 | 28 | puts "Broker product: #{connection.broker.product}, version: #{connection.broker.version}" 29 | puts "Connected to RabbitMQ? #{connection.broker.rabbitmq?}" 30 | 31 | puts 32 | puts "Broker supports publisher confirms? #{connection.broker.supports_publisher_confirmations?}" 33 | 34 | puts 35 | puts "Broker supports basic.nack? #{connection.broker.supports_basic_nack?}" 36 | 37 | puts 38 | puts "Broker supports consumer cancel notifications? #{connection.broker.supports_consumer_cancel_notifications?}" 39 | 40 | puts 41 | puts "Broker supports exchange-to-exchange bindings? #{connection.broker.supports_exchange_to_exchange_bindings?}" 42 | 43 | connection.disconnect { EventMachine.stop } 44 | end # AMQP.connect 45 | end # EventMachine.run 46 | -------------------------------------------------------------------------------- /examples/issues/amq_client_issue_7.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "Running amqp gem #{AMQP::VERSION}" 12 | 13 | EM.run do 14 | 15 | AMQP.connect do |conn| 16 | @amqp_connection = conn 17 | 18 | AMQP::Channel.new(@amqp_connection) do |channel| 19 | @amqp_channel = channel 20 | @amqp_exchange = @amqp_channel.topic 21 | 22 | EventMachine.add_periodic_timer(0) do 23 | random_binary_string = Array.new(rand(1000)) { rand(256) }.pack('c*') 24 | random_binary_string.force_encoding('BINARY') 25 | p random_binary_string 26 | @amqp_exchange.publish(random_binary_string, :routing_key => "a.my.pattern") 27 | end 28 | end 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /examples/issues/amq_protocol_issue_14.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts 13 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 14 | AMQP::Channel.new do |channel, open_ok| 15 | puts "Channel ##{channel.id} is now open!" 16 | 17 | channel.on_error do |ch, channel_close| 18 | puts "channel.close = #{channel_close.inspect}" 19 | puts "Handling a channel-level exception" 20 | end 21 | 22 | EventMachine.add_timer(0.4) do 23 | # this one works 24 | # binding = '12345678901234567890123456789012' 25 | 26 | # this one does not work 27 | binding = '123456789012345678901234567890123' 28 | queue = channel.queue 'test', :auto_delete => true, :durable => false 29 | queue.bind('amq.topic', :routing_key => binding) 30 | queue.unbind('amq.topic', :routing_key => binding) 31 | queue.unbind('amq.topic', :routing_key => binding) 32 | end 33 | end 34 | 35 | 36 | show_stopper = Proc.new do 37 | $stdout.puts "Stopping..." 38 | 39 | connection.close { 40 | EM.stop { exit } 41 | } 42 | end 43 | 44 | Signal.trap "INT", show_stopper 45 | EM.add_timer(2, show_stopper) 46 | end 47 | -------------------------------------------------------------------------------- /examples/issues/issue_121.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | 10 | 11 | require 'amqp' 12 | require 'amqp/extensions/rabbitmq' 13 | AMQP.start(:user => 'guest',:pass => 'guest',:vhost => '/') do |connection| 14 | channel = AMQP::Channel.new(connection) 15 | channel.queue("shuki_q",{:nowait => true,:passive=>false, :auto_delete=>false, :arguments=>{"x-expires"=>5600000}}) do |queue| 16 | queue.bind('raw.shuki',:routing_key => 'ShukiesTukies') 17 | puts "before subscribe" 18 | queue.subscribe(:ack => true) do |header, payload| 19 | puts "inside subscribe" 20 | p header.class 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /examples/issues/issue_75.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "Running amqp gem #{AMQP::VERSION}" 12 | 13 | AMQP.start(:host => "localhost") do |connection| 14 | channel = AMQP::Channel.new(connection) 15 | channel.fanout("logs.nad", :auto_delete => false) 16 | channel.fanout("logs.ad", :auto_delete => true) 17 | 18 | EM.add_timer(1) do 19 | connection.close do 20 | EM.stop { exit } 21 | end 22 | end 23 | end -------------------------------------------------------------------------------- /examples/issues/issue_79.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "Running amqp gem #{AMQP::VERSION}" 12 | 13 | 14 | 15 | AMQP.start do |conn| 16 | @amqp_connection = conn 17 | 18 | AMQP::Channel.new(@amqp_connection) do |channel| 19 | @amqp_channel = channel 20 | @amqp_exchange = @amqp_channel.topic 21 | 22 | AMQP::Queue.new(@amqp_channel, "") do |queue| 23 | queue.bind(@amqp_exchange, :routing_key => "a.*.pattern").subscribe(:ack => true) do |header, payload| 24 | p header.class 25 | p header.to_hash 26 | 27 | conn.close { EventMachine.stop } 28 | end 29 | end 30 | 31 | EventMachine.add_timer(0.3) do 32 | @amqp_exchange.publish "a message", :routing_key => "a.b.pattern" 33 | end 34 | end 35 | end -------------------------------------------------------------------------------- /examples/issues/issue_80.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "Running amqp gem #{AMQP::VERSION}" 12 | 13 | 14 | AMQP.start("amqp://guest:guest@localhost:5672") do |connection, open_ok| 15 | channel = AMQP::Channel.new(connection) 16 | channel.on_error { |ch, channel_close| puts "Error #{channel_close.inspect}" } 17 | queue = channel.queue("reset_test", :auto_delete => false, :durable=>true) 18 | exchange = channel.direct("foo") 19 | queue.bind(exchange) { puts 'Got bind ok'} 20 | 21 | EM.add_timer(2) do 22 | channel.reset 23 | queue = channel.queue("reset_test", :auto_delete => false, :durable=>true) 24 | exchange = channel.direct("foo") 25 | queue.unbind(exchange) { puts 'Got unbind ok'} 26 | end 27 | 28 | show_stopper = Proc.new do 29 | $stdout.puts "Stopping..." 30 | 31 | queue.delete 32 | exchange.delete 33 | connection.close { 34 | EM.stop { exit } 35 | } 36 | end 37 | 38 | Signal.trap "INT", show_stopper 39 | EM.add_timer(4, show_stopper) 40 | end 41 | -------------------------------------------------------------------------------- /examples/issues/issue_93.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "rubygems" 5 | require 'amqp' 6 | 7 | puts "Running amqp gem #{AMQP::VERSION}" 8 | 9 | 10 | AMQP.start("amqp://guest:guest@localhost:5672") do |connection, open_ok| 11 | ch = AMQP::Channel.new(connection) 12 | ch.direct("amqpgem.issues.93.1") 13 | ch.direct("amqpgem.issues.93.2", :auto_delete => false) 14 | ch.direct("amqpgem.issues.93.3") do |ex, declare_ok| 15 | end 16 | ch.direct("amqpgem.issues.93.4", :auto_delete => false) do |ex, declare_ok| 17 | end 18 | ch.direct("amqpgem.issues.93.5", :auto_delete => true) 19 | ch.direct("amqpgem.issues.93.6", :auto_delete => true) do |ex, declare_ok| 20 | end 21 | 22 | puts "Done" 23 | end -------------------------------------------------------------------------------- /examples/issues/issue_94.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | if defined?(Bundler) 5 | Bundler.setup 6 | else 7 | require "rubygems" 8 | end 9 | require "amqp" 10 | 11 | puts "Running amqp gem #{AMQP::VERSION}" 12 | 13 | AMQP.start(:host => '127.0.0.1') do |connection| 14 | channel = AMQP::Channel.new(connection) 15 | exchange = channel.direct("") 16 | queue = channel.queue("indexer_queue", { :durable => true }) 17 | 18 | EM.add_periodic_timer(1) { 19 | queue.status do |num_messages, num_consumers| 20 | puts "msgs:#{num_messages}" 21 | end 22 | } 23 | end -------------------------------------------------------------------------------- /examples/patterns/command/consumer.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__) 4 | 5 | require "amqp" 6 | require "yaml" 7 | 8 | t = Thread.new { EventMachine.run } 9 | sleep(0.5) 10 | 11 | 12 | connection = AMQP.connect 13 | channel = AMQP::Channel.new(connection, :auto_recovery => true) 14 | 15 | channel.prefetch(1) 16 | 17 | # Acknowledgements are good for letting the server know 18 | # that the task is finished. If the consumer doesn't send 19 | # the acknowledgement, then the task is considered to be unfinished 20 | # and will be requeued when consumer closes AMQP connection (because of a crash, for example). 21 | channel.queue("amqpgem.examples.patterns.command", :durable => true, :auto_delete => false).subscribe(:ack => true) do |metadata, payload| 22 | case metadata.type 23 | when "gems.install" 24 | data = YAML.load(payload) 25 | puts "[gems.install] Received a 'gems.install' request with #{data.inspect}" 26 | 27 | # just to demonstrate a realistic example 28 | shellout = "gem install #{data[:gem]} --version '#{data[:version]}'" 29 | puts "[gems.install] Executing #{shellout}"; system(shellout) 30 | 31 | puts 32 | puts "[gems.install] Done" 33 | puts 34 | else 35 | puts "[commands] Unknown command: #{metadata.type}" 36 | end 37 | 38 | # message is processed, acknowledge it so that broker discards it 39 | metadata.ack 40 | end 41 | 42 | puts "[boot] Ready" 43 | Signal.trap("INT") { connection.close { EventMachine.stop } } 44 | t.join 45 | 46 | -------------------------------------------------------------------------------- /examples/patterns/command/producer.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__) 4 | 5 | require "amqp" 6 | require "yaml" 7 | 8 | t = Thread.new { EventMachine.run } 9 | sleep(0.5) 10 | 11 | connection = AMQP.connect 12 | channel = AMQP::Channel.new(connection) 13 | 14 | # publish new commands every few seconds 15 | EventMachine.add_periodic_timer(10.0) do 16 | puts "Publishing a command (gems.install)" 17 | payload = { :gem => "rack", :version => "~> 1.3.0" }.to_yaml 18 | 19 | channel.default_exchange.publish(payload, 20 | :type => "gems.install", 21 | :routing_key => "amqpgem.examples.patterns.command") 22 | end 23 | 24 | puts "[boot] Ready. Will be publishing commands every 10 seconds." 25 | Signal.trap("INT") { connection.close { EventMachine.stop } } 26 | t.join 27 | -------------------------------------------------------------------------------- /examples/patterns/event/consumer.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__) 4 | 5 | require "amqp" 6 | require "yaml" 7 | 8 | t = Thread.new { EventMachine.run } 9 | sleep(0.5) 10 | 11 | 12 | connection = AMQP.connect 13 | channel = AMQP::Channel.new(connection, :auto_recovery => true) 14 | channel.on_error do |ch, channel_close| 15 | raise "Channel-level exception: #{channel_close.reply_text}" 16 | end 17 | 18 | channel.prefetch(1) 19 | 20 | channel.queue("", :durable => false, :auto_delete => true).bind("amqpgem.patterns.events").subscribe do |metadata, payload| 21 | begin 22 | body = YAML.load(payload) 23 | 24 | case metadata.type 25 | when "widgets.created" then 26 | puts "A widget #{body[:id]} was created" 27 | when "widgets.destroyed" then 28 | puts "A widget #{body[:id]} was destroyed" 29 | when "files.created" then 30 | puts "A new file (#{body[:filename]}, #{body[:sha1]}) was uploaded" 31 | when "files.indexed" then 32 | puts "A new file (#{body[:filename]}, #{body[:sha1]}) was indexed" 33 | else 34 | puts "[warn] Do not know how to handle event of type #{metadata.type}" 35 | end 36 | rescue Exception => e 37 | puts "[error] Could not handle event of type #{metadata.type}: #{e.inspect}" 38 | end 39 | end 40 | 41 | puts "[boot] Ready" 42 | Signal.trap("INT") { connection.close { EventMachine.stop } } 43 | t.join 44 | -------------------------------------------------------------------------------- /examples/patterns/event/producer.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__) 4 | 5 | require "amqp" 6 | require "yaml" 7 | 8 | t = Thread.new { EventMachine.run } 9 | sleep(0.5) 10 | 11 | connection = AMQP.connect 12 | channel = AMQP::Channel.new(connection) 13 | exchange = channel.fanout("amqpgem.patterns.events", :durable => true, :auto_delete => false) 14 | 15 | 16 | EVENTS = { 17 | "pages.show" => { 18 | :url => "https://mysite.local/widgets/81772", 19 | :referrer => "http://www.google.com/search?client=safari&rls=en&q=widgets&ie=UTF-8&oe=UTF-8" 20 | }, 21 | "widgets.created" => { 22 | :id => 10, 23 | :shape => "round", 24 | :owner_id => 1000 25 | }, 26 | "widgets.destroyed" => { 27 | :id => 10, 28 | :person_id => 1000 29 | }, 30 | "files.created" => { 31 | :sha1 => "1a62429f47bc8b405d17e84b648f2fbebc555ee5", 32 | :filename => "document.pdf" 33 | }, 34 | "files.indexed" => { 35 | :sha1 => "1a62429f47bc8b405d17e84b648f2fbebc555ee5", 36 | :filename => "document.pdf", 37 | :runtime => 1.7623, 38 | :shared => "shard02" 39 | } 40 | } 41 | 42 | def generate_event 43 | n = (EVENTS.size * Kernel.rand).floor 44 | type = EVENTS.keys[n] 45 | payload = EVENTS[type] 46 | 47 | [type, payload] 48 | end 49 | 50 | # broadcast events 51 | EventMachine.add_periodic_timer(2.0) do 52 | event_type, payload = generate_event 53 | 54 | puts "Publishing a new event of type #{event_type}" 55 | exchange.publish(payload.to_yaml, :type => event_type) 56 | end 57 | 58 | puts "[boot] Ready. Will be publishing events every few seconds." 59 | Signal.trap("INT") { connection.close { EventMachine.stop } } 60 | t.join 61 | -------------------------------------------------------------------------------- /examples/patterns/request_reply/client.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__) 4 | 5 | require "amqp" 6 | 7 | EventMachine.run do 8 | connection = AMQP.connect 9 | channel = AMQP::Channel.new(connection) 10 | 11 | replies_queue = channel.queue("", :exclusive => true, :auto_delete => true) 12 | replies_queue.subscribe do |metadata, payload| 13 | puts "[response] Response for #{metadata.correlation_id}: #{payload.inspect}" 14 | end 15 | 16 | # request time from a peer every 3 seconds 17 | EventMachine.add_periodic_timer(3.0) do 18 | puts "[request] Sending a request..." 19 | channel.default_exchange.publish("get.time", 20 | :routing_key => "amqpgem.examples.services.time", 21 | :message_id => Kernel.rand(10101010).to_s, 22 | :reply_to => replies_queue.name) 23 | end 24 | 25 | 26 | 27 | Signal.trap("INT") { connection.close { EventMachine.stop } } 28 | end 29 | -------------------------------------------------------------------------------- /examples/patterns/request_reply/server.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | $LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__) 4 | 5 | require "amqp" 6 | 7 | EventMachine.run do 8 | connection = AMQP.connect 9 | channel = AMQP::Channel.new(connection) 10 | 11 | requests_queue = channel.queue("amqpgem.examples.services.time", :exclusive => true, :auto_delete => true) 12 | requests_queue.subscribe(:ack => true) do |metadata, payload| 13 | puts "[requests] Got a request #{metadata.message_id}. Sending a reply..." 14 | channel.default_exchange.publish(Time.now.to_s, 15 | :routing_key => metadata.reply_to, 16 | :correlation_id => metadata.message_id, 17 | :mandatory => true) 18 | 19 | metadata.ack 20 | end 21 | 22 | 23 | 24 | Signal.trap("INT") { connection.close { EventMachine.stop } } 25 | end 26 | -------------------------------------------------------------------------------- /examples/publishing/publishing_a_one_off_message.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Publishing and immediately stopping the event loop in the callback" 12 | puts 13 | 14 | # WARNING: this example is born out of http://bit.ly/j6v1Uz (#67) and 15 | # by no means a demonstration of how you should go about publishing one-off messages. 16 | # If durability is a concern, please read our "Durability and message persistence" guide at 17 | # http://bit.ly/lQP1Al 18 | 19 | EventMachine.run do 20 | connection = AMQP.connect(:host => '127.0.0.1') 21 | channel = AMQP::Channel.new(connection) 22 | channel.on_error do |ch, channel_close| 23 | puts "Channel-level error: #{channel_close.reply_text}, shutting down..." 24 | connection.close { EventMachine.stop } 25 | end 26 | 27 | # topic exchange is used just as example. Often it is more convenient to use default exchange, 28 | # see http://bit.ly/amqp-gem-default-exchange 29 | exchange = channel.topic("a.topic", :durable => true, :auto_delete => true) 30 | queue = channel.queue("a.queue", :auto_delete => true).bind(exchange, :routing_key => "events.#") 31 | 32 | exchange.publish('hello world', :routing_key => "events.hits.homepage", :persistent => true, :nowait => false) do 33 | puts "About to disconnect..." 34 | connection.close { EventMachine.stop } 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /examples/publishing/publishing_callback.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Using a callback to #publish. It is run on the _next_ EventMachine loop run." 12 | puts 13 | 14 | EventMachine.run do 15 | connection = AMQP.connect(:host => '127.0.0.1') 16 | channel = AMQP::Channel.new(connection) 17 | channel.on_error do |ch, channel_close| 18 | puts "Channel-level error: #{channel_close.reply_text}, shutting down..." 19 | connection.close { EventMachine.stop } 20 | end 21 | 22 | queue = channel.queue("amqpgem.examples.publishing.queue1", :auto_delete => true) 23 | exchange = channel.fanout("amqpgem.examples.topic", :durable => true, :auto_delete => true) 24 | 25 | queue.bind(exchange, :routing_key => "some_topic") 26 | 27 | 28 | # Don't be deceived: this callback is run on the next event loop tick. There is no guarantee that your 29 | # data was sent: there is buffering going on on multiple layers (C++ core of EventMachine, libc functions, 30 | # kernel uses buffering for many I/O system calls). 31 | # 32 | # This callback is simply for convenience. In a distributed environment, the only way to know when your data 33 | # is sent is when you receive an acknowledgement. TCP works that way. MK. 34 | 35 | 100.times do |i| 36 | exchange.publish("hello world #{i}", :routing_key => "some_topic", :persistent => true) do 37 | puts "Callback #{i} has fired" 38 | end 39 | end 40 | 41 | exchange.publish("hello world 101", :routing_key => "some_topic", :persistent => false) do 42 | puts "Callback 101 has fired" 43 | end 44 | 45 | exchange.publish("hello world 102", :routing_key => "some_topic", :persistent => true) do 46 | puts "Callback 102 has fired" 47 | end 48 | 49 | EventMachine.add_timer(1) do 50 | connection.close { EventMachine.stop } 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /examples/publishing/returned_messages.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Handling returned messages" 12 | puts 13 | 14 | AMQP.start(:host => '127.0.0.1') do |connection| 15 | channel = AMQP.channel 16 | channel.on_error { |ch, channel_close| EventMachine.stop; raise "channel error: #{channel_close.reply_text}" } 17 | 18 | exchange = channel.fanout("amq.fanout") 19 | exchange.on_return do |basic_return, metadata, payload| 20 | puts "#{payload} was returned! reply_code = #{basic_return.reply_code}, reply_text = #{basic_return.reply_text}" 21 | end 22 | 23 | EventMachine.add_timer(0.3) { 24 | 10.times do |i| 25 | exchange.publish("Message ##{i}") 26 | end 27 | } 28 | 29 | EventMachine.add_timer(2) { 30 | connection.close { EventMachine.stop } 31 | } 32 | end 33 | -------------------------------------------------------------------------------- /examples/publishing/simplistic_scatter_gather.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | AMQP.start do |session| 13 | ch = AMQP::Channel.new(session) 14 | exchange = ch.fanout("amq.fanout") 15 | reply_exchange = ch.default_exchange 16 | 17 | ch.queue("", :exclusive => true) do |q1| 18 | q1.bind(exchange).subscribe do |header, payload| 19 | v = rand 20 | 21 | puts "Replying to #{header.message_id} with #{v}" 22 | reply_exchange.publish(v, :routing_key => header.reply_to, :message_id => header.message_id) 23 | end 24 | end 25 | ch.queue("", :exclusive => true) do |q2| 26 | q2.bind(exchange).subscribe do |header, payload| 27 | v = rand 28 | 29 | puts "Replying to #{header.message_id} with #{v}" 30 | reply_exchange.publish(v, :routing_key => header.reply_to, :message_id => header.message_id) 31 | end 32 | end 33 | ch.queue("", :exclusive => true) do |q3| 34 | q3.bind(exchange).subscribe do |header, payload| 35 | v = rand 36 | 37 | puts "Replying to #{header.message_id} with #{v}" 38 | reply_exchange.publish(v, :routing_key => header.reply_to, :message_id => header.message_id) 39 | end 40 | end 41 | 42 | 43 | requests = Hash.new 44 | 45 | EventMachine.add_timer(0.5) do 46 | ch.queue("", :exlusive => true) do |q| 47 | q.subscribe do |header, payload| 48 | requests[header.message_id].push(payload) 49 | 50 | puts "Got a reply for #{header.message_id}" 51 | 52 | if requests[header.message_id].size == 3 53 | puts "Gathered all 3 responses: #{requests[header.message_id].join(', ')}" 54 | requests[header.message_id].clear 55 | end 56 | end 57 | 58 | 59 | message_id = "__message #{rand}__" 60 | requests[message_id] = Array.new 61 | 62 | exchange.publish("a request", :reply_to => q.name, :message_id => message_id) 63 | end 64 | end 65 | 66 | 67 | EventMachine.add_timer(2) do 68 | session.close { EventMachine.stop } 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /examples/queues/accessing_message_metadata.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | connection = AMQP.connect(:host => '127.0.0.1') 13 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 14 | 15 | channel = AMQP::Channel.new(connection) 16 | queue = channel.queue("amqpgem.examples.hello_world", :auto_delete => true) 17 | exchange = channel.direct("amq.direct") 18 | 19 | queue.bind(exchange, :routing_key => "amqpgem.key") 20 | 21 | channel.on_error do |ch, channel_close| 22 | puts channel_close.reply_text 23 | connection.close { EventMachine.stop } 24 | end 25 | 26 | queue.subscribe do |metadata, payload| 27 | puts "metadata.routing_key : #{metadata.routing_key}" 28 | puts "metadata.content_type: #{metadata.content_type}" 29 | puts "metadata.priority : #{metadata.priority}" 30 | puts "metadata.headers : #{metadata.headers.inspect}" 31 | puts "metadata.timestamp : #{metadata.timestamp.inspect}" 32 | puts "metadata.type : #{metadata.type}" 33 | puts "metadata.consumer_tag: #{metadata.consumer_tag}" 34 | puts "metadata.delivery_tag: #{metadata.delivery_tag}" 35 | puts "metadata.redelivered : #{metadata.redelivered?}" 36 | 37 | puts "metadata.app_id : #{metadata.app_id}" 38 | puts "metadata.correlation_id: #{metadata.correlation_id}" 39 | puts "metadata.exchange : #{metadata.exchange}" 40 | puts 41 | puts "Received a message: #{payload}. Disconnecting..." 42 | 43 | connection.close { EventMachine.stop } 44 | end 45 | 46 | exchange.publish("Hey, what a great view!", 47 | :app_id => "amqpgem.example", 48 | :priority => 8, 49 | :type => "kinda.checkin", 50 | :correlation_id => "b907b65a4876fc0d4b12fbdef1b41fb0a9876a94", 51 | # headers table keys can be anything 52 | :headers => { 53 | :coordinates => { 54 | :latitude => 59.35, 55 | :longitude => 18.066667 56 | }, 57 | :participants => 11, 58 | :venue => "Stockholm" 59 | }, 60 | :timestamp => Time.now.to_i, 61 | :routing_key => "amqpgem.key") 62 | end 63 | -------------------------------------------------------------------------------- /examples/queues/automatic_binding_for_default_direct_exchange.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | if RUBY_VERSION == "1.8.7" 12 | class Array 13 | alias sample choice 14 | end 15 | end 16 | 17 | puts "=> Default exchange example" 18 | puts 19 | AMQP.start(:host => 'localhost') do |connection| 20 | ch = AMQP::Channel.new(connection) 21 | 22 | queue1 = ch.queue("queue1").subscribe do |payload| 23 | puts "[#{queue1.name}] => #{payload}" 24 | end 25 | queue2 = ch.queue("queue2").subscribe do |payload| 26 | puts "[#{queue2.name}] => #{payload}" 27 | end 28 | queue3 = ch.queue("queue3").subscribe do |payload| 29 | puts "[#{queue3.name}] => #{payload}" 30 | end 31 | queues = [queue1, queue2, queue3] 32 | 33 | # Rely on default direct exchange binding, see section 2.1.2.4 Automatic Mode in AMQP 0.9.1 spec. 34 | exchange = AMQP::Exchange.default 35 | EM.add_periodic_timer(1) do 36 | q = queues.sample 37 | 38 | $stdout.puts "Publishing to default exchange with routing key = #{q.name}..." 39 | exchange.publish "Some payload from #{Time.now.to_i}", :routing_key => q.name 40 | end 41 | 42 | 43 | show_stopper = Proc.new do 44 | queue1.delete 45 | queue2.delete 46 | queue3.delete 47 | 48 | $stdout.puts "Stopping..." 49 | connection.close { 50 | EM.stop { exit } 51 | } 52 | end 53 | 54 | Signal.trap "INT", &show_stopper 55 | Signal.trap "TERM", &show_stopper 56 | EM.add_timer(7, show_stopper) 57 | end 58 | -------------------------------------------------------------------------------- /examples/queues/basic_get.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | if RUBY_VERSION == "1.8.7" 12 | class Array 13 | alias sample choice 14 | end 15 | end 16 | 17 | 18 | puts "=> basic.get example" 19 | puts 20 | AMQP.start(:host => 'localhost') do |connection| 21 | channel = AMQP::Channel.new 22 | 23 | queue_name = "amqpgem.integration.basic.get.queue" 24 | expected_number_of_messages = 50 25 | 26 | exchange = channel.fanout("amqpgem.integration.basic.get.fanout", :auto_delete => true) 27 | queue = channel.queue(queue_name, :auto_delete => true) 28 | 29 | queue.bind(exchange) do 30 | puts "Bound #{exchange.name} => #{queue.name}" 31 | end 32 | expected_number_of_messages.times do |i| 33 | print "." 34 | exchange.publish(Time.now.to_i.to_s + "_#{i}", :key => queue_name) 35 | end 36 | $stdout.flush 37 | 38 | sleep 1 39 | 40 | queue.status do |number_of_messages, number_of_consumers| 41 | puts "# of messages on status = #{number_of_messages}" 42 | end 43 | 44 | queue.status do |number_of_messages, number_of_consumers| 45 | puts "# of messages on status = #{number_of_messages}" 46 | expected_number_of_messages.times do 47 | queue.pop do |headers, payload| 48 | puts "=> With payload #{payload.inspect}, routing key: #{headers.routing_key}, #{headers.message_count} message(s) left in the queue" 49 | end # pop 50 | end 51 | end 52 | 53 | 54 | show_stopper = Proc.new do 55 | $stdout.puts "Stopping..." 56 | connection.close { 57 | EM.stop { exit } 58 | } 59 | end 60 | 61 | Signal.trap "INT", show_stopper 62 | EM.add_timer(2, show_stopper) 63 | end 64 | -------------------------------------------------------------------------------- /examples/queues/cancel_default_consumer.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | EventMachine.run do 12 | connection = AMQP.connect(:host => '127.0.0.1') 13 | puts "Connected to RabbitMQ. Running #{AMQP::VERSION} version of the gem..." 14 | 15 | channel = AMQP::Channel.new(connection) 16 | queue = channel.queue("amqpgem.examples.hello_world", :auto_delete => true) 17 | exchange = channel.direct("amq.direct") 18 | 19 | queue.bind(exchange, :routing_key => "amqpgem.key") 20 | 21 | channel.on_error do |ch, channel_close| 22 | puts channel_close.reply_text 23 | connection.close { EventMachine.stop } 24 | end 25 | 26 | queue.subscribe do |metadata, payload| 27 | puts "Received a message: #{payload}." 28 | end 29 | 30 | EventMachine.add_periodic_timer(1.0) do 31 | exchange.publish("Hey, what a great view!", :routing_key => "amqpgem.key") 32 | end 33 | 34 | EventMachine.add_timer(3.0) do 35 | queue.unsubscribe do 36 | puts "Cancelled default consumer..." 37 | connection.close { EventMachine.stop } 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /examples/queues/declare_a_queue_without_assignment.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue#initialize example that uses a block" 13 | puts 14 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" 17 | 18 | AMQP::Queue.new(channel, "", :auto_delete => true) do |queue| 19 | puts "#{queue.name} is ready to go" 20 | end 21 | 22 | AMQP::Queue.new(channel, "", :auto_delete => true) do |queue, declare_ok| 23 | puts "#{queue.name} is ready to go. AMQP method: #{declare_ok.inspect}" 24 | end 25 | 26 | channel.queue("", :auto_delete => true) do |queue, declare_ok| 27 | puts "#{queue.name} is ready to go. AMQP method: #{declare_ok.inspect}" 28 | end 29 | end 30 | 31 | 32 | show_stopper = Proc.new do 33 | $stdout.puts "Stopping..." 34 | 35 | connection.close { 36 | EM.stop { exit } 37 | } 38 | end 39 | 40 | Signal.trap "INT", show_stopper 41 | EM.add_timer(2, show_stopper) 42 | end 43 | -------------------------------------------------------------------------------- /examples/queues/declare_and_bind_a_server_named_queue.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | 12 | puts "=> Queue#initialize example that uses a block" 13 | puts 14 | AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672") do |connection, open_ok| 15 | AMQP::Channel.new do |channel, open_ok| 16 | puts "Channel ##{channel.id} is now open!" if channel.open? 17 | 18 | xchange = channel.fanout("amq.fanout", :nowait => true) 19 | q = AMQP::Queue.new(channel, "", :auto_delete => true) 20 | 21 | 22 | EM.add_timer(0.5) do 23 | puts "Channel ##{channel.id} is still open!" if channel.open? 24 | q.bind(xchange).subscribe do |header, payload| 25 | puts "Got a payload: #{payload}" 26 | end 27 | 28 | EventMachine.add_timer(0.3) { xchange.publish("à bientôt!") } 29 | end 30 | end 31 | 32 | 33 | show_stopper = Proc.new do 34 | $stdout.puts "Stopping..." 35 | 36 | connection.close { 37 | EM.stop { exit } 38 | } 39 | end 40 | 41 | Signal.trap "INT", show_stopper 42 | EM.add_timer(2, show_stopper) 43 | end 44 | -------------------------------------------------------------------------------- /examples/queues/queue_status.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Queue#status example" 12 | puts 13 | AMQP.start(:host => 'localhost') do |connection| 14 | channel = AMQP::Channel.new(connection) 15 | 16 | queue_name = "amqpgem.integration.queue.status.queue" 17 | exchange = channel.fanout("amqpgem.integration.queue.status.fanout", :auto_delete => true) 18 | queue = channel.queue(queue_name, :auto_delete => true).bind(exchange) 19 | 20 | 100.times do |i| 21 | print "." 22 | exchange.publish(Time.now.to_i.to_s + "_#{i}", :key => queue_name) 23 | end 24 | $stdout.flush 25 | 26 | EventMachine.add_timer(0.5) do 27 | queue.status do |number_of_messages, number_of_consumers| 28 | puts 29 | puts "# of messages on status = #{number_of_messages}" 30 | puts 31 | queue.purge 32 | end 33 | end 34 | 35 | 36 | show_stopper = Proc.new do 37 | $stdout.puts "Stopping..." 38 | connection.close { EventMachine.stop } 39 | end 40 | 41 | Signal.trap "INT", show_stopper 42 | EventMachine.add_timer(2, show_stopper) 43 | end 44 | -------------------------------------------------------------------------------- /examples/queues/rejecting_messages_without_requeueuing.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | if RUBY_VERSION == "1.8.7" 12 | class Array 13 | alias sample choice 14 | end 15 | end 16 | 17 | 18 | puts "=> Queue#status example" 19 | puts 20 | AMQP.start(:host => 'localhost') do |connection| 21 | channel = AMQP::Channel.new(connection) 22 | 23 | exchange = channel.fanout("amqpgem.integration.queue.status.fanout", :auto_delete => true) 24 | queue = channel.queue("amqpgem.integration.queue.status.queue", :auto_delete => true) 25 | 26 | queue.bind(exchange).subscribe do |metadata, payload| 27 | puts "Rejecting #{payload}" 28 | channel.reject(metadata.delivery_tag) 29 | end 30 | 31 | 100.times do |i| 32 | print "." 33 | exchange.publish(Time.now.to_i.to_s + "_#{i}", :key => queue.name) 34 | end 35 | $stdout.flush 36 | 37 | 38 | show_stopper = Proc.new do 39 | $stdout.puts "Stopping..." 40 | connection.close { 41 | EventMachine.stop { exit } 42 | } 43 | end 44 | 45 | Signal.trap "INT", show_stopper 46 | EventMachine.add_timer(2, show_stopper) 47 | end 48 | -------------------------------------------------------------------------------- /examples/rack/publish_a_message_on_request/thin.ru: -------------------------------------------------------------------------------- 1 | use Rack::CommonLogger 2 | 3 | require "bundler" 4 | Bundler.setup 5 | 6 | $:.unshift(File.expand_path("../../../../lib", __FILE__)) 7 | 8 | require 'amqp' 9 | require 'amqp/utilities/event_loop_helper' 10 | 11 | puts "EventMachine.reactor_running? => #{EventMachine.reactor_running?.inspect}" 12 | 13 | AMQP::Utilities::EventLoopHelper.run do 14 | AMQP.start 15 | 16 | exchange = AMQP.channel.fanout("amq.fanout") 17 | 18 | q = AMQP.channel.queue("", :auto_delete => true, :exclusive => true) 19 | q.bind(exchange) 20 | AMQP::channel.default_exchange.publish("Started!", :routing_key => q.name) 21 | end 22 | 23 | app = proc do |env| 24 | AMQP.channel.fanout("amq.fanout").publish("Served a request at (#{Time.now.to_i})") 25 | 26 | [ 27 | 200, # Status code 28 | { # Response headers 29 | 'Content-Type' => 'text/html', 30 | 'Content-Length' => '2', 31 | }, 32 | ['hi'] # Response body 33 | ] 34 | end 35 | 36 | run app -------------------------------------------------------------------------------- /examples/routing/fanout_routing.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require "amqp" 10 | 11 | EventMachine.run do 12 | AMQP.connect("amqp://dev.rabbitmq.com") do |connection| 13 | channel = AMQP::Channel.new(connection) 14 | exchange = channel.topic("amqpgem.examples.routing.fanout_routing", :auto_delete => true) 15 | 16 | # Subscribers. 17 | 10.times do 18 | q = channel.queue("", :exclusive => true, :auto_delete => true).bind(exchange) 19 | q.subscribe do |payload| 20 | puts "Queue #{q.name} received #{payload}" 21 | end 22 | end 23 | 24 | # Publish some test data in a bit, after all queues are declared & bound 25 | EventMachine.add_timer(1.2) { exchange.publish "Hello, fanout exchanges world!" } 26 | 27 | 28 | show_stopper = Proc.new { connection.close { EventMachine.stop } } 29 | 30 | Signal.trap "TERM", show_stopper 31 | EM.add_timer(3, show_stopper) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /examples/routing/headers_routing.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Headers routing example" 12 | puts 13 | AMQP.start do |connection| 14 | channel = AMQP::Channel.new(connection) 15 | channel.on_error do |ch, channel_close| 16 | puts "A channel-level exception: #{channel_close.inspect}" 17 | end 18 | 19 | exchange = channel.headers("amq.match", :durable => true) 20 | 21 | channel.queue("", :auto_delete => true).bind(exchange, :arguments => { 'x-match' => 'all', :arch => "ia64", :os => 'linux' }).subscribe do |metadata, payload| 22 | puts "[linux/ia64] Got a message: #{payload}" 23 | end 24 | channel.queue("", :auto_delete => true).bind(exchange, :arguments => { 'x-match' => 'all', :arch => "x86", :os => 'linux' }).subscribe do |metadata, payload| 25 | puts "[linux/x86] Got a message: #{payload}" 26 | end 27 | channel.queue("", :auto_delete => true).bind(exchange, :arguments => { :os => 'linux'}).subscribe do |metadata, payload| 28 | puts "[linux] Got a message: #{payload}" 29 | end 30 | channel.queue("", :auto_delete => true).bind(exchange, :arguments => { 'x-match' => 'any', :os => 'macosx', :cores => 8 }).subscribe do |metadata, payload| 31 | puts "[macosx|octocore] Got a message: #{payload}" 32 | end 33 | channel.queue("", :auto_delete => true).bind(exchange, :arguments => { :package => { :name => 'riak', :version => '0.14.2' } }).subscribe do |metadata, payload| 34 | puts "[riak/0.14.2] Got a message: #{payload}" 35 | end 36 | 37 | EventMachine.add_timer(0.5) do 38 | exchange.publish "For linux/ia64", :headers => { :arch => "ia64", :os => 'linux' } 39 | exchange.publish "For linux/x86", :headers => { :arch => "x86", :os => 'linux' } 40 | exchange.publish "For linux", :headers => { :os => 'linux' } 41 | exchange.publish "For OS X", :headers => { :os => 'macosx' } 42 | exchange.publish "For solaris/ia64", :headers => { :os => 'solaris', :arch => 'ia64' } 43 | exchange.publish "For ocotocore", :headers => { :cores => 8 } 44 | 45 | exchange.publish "For nodes with Riak 0.14.2", :headers => { :package => { :name => 'riak', :version => '0.14.2' } } 46 | end 47 | 48 | 49 | show_stopper = Proc.new do 50 | $stdout.puts "Stopping..." 51 | connection.close { EventMachine.stop } 52 | end 53 | 54 | Signal.trap "INT", show_stopper 55 | EventMachine.add_timer(2, show_stopper) 56 | end 57 | -------------------------------------------------------------------------------- /examples/routing/pubsub.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require "amqp" 10 | 11 | EventMachine.run do 12 | AMQP.connect do |connection| 13 | channel = AMQP::Channel.new(connection) 14 | exchange = channel.topic("pub/sub") 15 | 16 | # Subscribers. 17 | channel.queue("Everything about development").bind(exchange, :routing_key => "technology.dev.#").subscribe do |payload| 18 | puts "A new dev post: '#{payload}'" 19 | end 20 | channel.queue("Everything about rubies").bind(exchange, :routing_key => "#.ruby").subscribe do |headers, payload| 21 | puts "A new post about rubies: '#{payload}', routing key = #{headers.routing_key}" 22 | end 23 | 24 | # Let's publish some test data. 25 | exchange.publish "Ruby post", :routing_key => "technology.dev.ruby" 26 | exchange.publish "Erlang post", :routing_key => "technology.dev.erlang" 27 | exchange.publish "Sinatra post", :routing_key => "technology.web.ruby" 28 | exchange.publish "Jewelery post", :routing_key => "jewelery.ruby" 29 | 30 | 31 | 32 | show_stopper = Proc.new { 33 | connection.close do 34 | EM.stop 35 | end 36 | } 37 | 38 | Signal.trap "INT", show_stopper 39 | Signal.trap "TERM", show_stopper 40 | 41 | EM.add_timer(1, show_stopper) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /examples/routing/round_robin_with_direct_exchange.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require "amqp" 10 | 11 | EventMachine.run do 12 | AMQP.connect do |connection| 13 | channel1 = AMQP::Channel.new(connection) 14 | channel2 = AMQP::Channel.new(connection) 15 | exchange = channel1.direct("amqpgem.examples.exchanges.direct", :auto_delete => true) 16 | 17 | q1 = channel1.queue("amqpgem.examples.queues.shared", :auto_delete => true).bind(exchange, :routing_key => "shared.key") 18 | q1.subscribe do |payload| 19 | puts "Queue #{q1.name} on channel 1 received #{payload}" 20 | end 21 | 22 | # since the queue is shared, binding here is redundant but we will leave it in for completeness. 23 | q2 = channel2.queue("amqpgem.examples.queues.shared", :auto_delete => true).bind(exchange, :routing_key => "shared.key") 24 | q2.subscribe do |payload| 25 | puts "Queue #{q2.name} on channel 2 received #{payload}" 26 | end 27 | 28 | # Publish some test data in a bit, after all queues are declared & bound 29 | EventMachine.add_timer(1.2) do 30 | 5.times { |i| exchange.publish("Hello #{i}, direct exchanges world!", :routing_key => "shared.key") } 31 | end 32 | 33 | 34 | show_stopper = Proc.new { connection.close { EventMachine.stop } } 35 | 36 | Signal.trap "TERM", show_stopper 37 | EM.add_timer(3, show_stopper) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /examples/routing/round_robin_with_the_default_exchange.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require "amqp" 10 | 11 | EventMachine.run do 12 | AMQP.connect do |connection| 13 | channel1 = AMQP::Channel.new(connection) 14 | channel2 = AMQP::Channel.new(connection) 15 | exchange = channel1.default_exchange 16 | 17 | q1 = channel1.queue("amqpgem.examples.queues.shared", :auto_delete => true) 18 | q1.subscribe do |payload| 19 | puts "Queue #{q1.name} on channel 1 received #{payload}" 20 | end 21 | 22 | q2 = channel2.queue("amqpgem.examples.queues.shared", :auto_delete => true) 23 | q2.subscribe do |payload| 24 | puts "Queue #{q2.name} on channel 2 received #{payload}" 25 | end 26 | 27 | # Publish some test data in a bit, after all queues are declared & bound 28 | EventMachine.add_timer(1.2) do 29 | 5.times { |i| exchange.publish("Hello #{i}, direct exchanges world!", :routing_key => "amqpgem.examples.queues.shared") } 30 | end 31 | 32 | 33 | show_stopper = Proc.new { connection.close { EventMachine.stop } } 34 | 35 | Signal.trap "TERM", show_stopper 36 | EM.add_timer(3, show_stopper) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /examples/routing/unroutable_mandatory_message_is_returned.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | require 'amqp' 10 | 11 | puts "=> Handling a returned unroutable message that was published as mandatory" 12 | puts 13 | 14 | AMQP.start(:host => '127.0.0.1') do |connection| 15 | channel = AMQP.channel 16 | channel.on_error { |ch, channel_close| EventMachine.stop; raise "channel error: #{channel_close.reply_text}" } 17 | 18 | # this exchange has no bindings, so messages published to it cannot be routed. 19 | exchange = channel.fanout("amqpgem.examples.fanout", :auto_delete => true) 20 | exchange.on_return do |basic_return, metadata, payload| 21 | puts "#{payload} was returned! reply_code = #{basic_return.reply_code}, reply_text = #{basic_return.reply_text}" 22 | end 23 | 24 | EventMachine.add_timer(0.3) { 25 | 10.times do |i| 26 | exchange.publish("Message ##{i}", :mandatory => true) 27 | end 28 | } 29 | 30 | EventMachine.add_timer(2) { 31 | connection.close { EventMachine.stop } 32 | } 33 | end 34 | -------------------------------------------------------------------------------- /examples/tls/using_tls.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require "bundler" 5 | Bundler.setup 6 | 7 | $:.unshift(File.expand_path("../../../lib", __FILE__)) 8 | 9 | examples_dir = File.join(File.dirname(File.expand_path(__FILE__)), "..") 10 | 11 | certificate_chain_file_path = File.join(examples_dir, "tls_certificates", "client", "cert.pem") 12 | client_private_key_file_path = File.join(examples_dir, "tls_certificates", "client", "key.pem") 13 | 14 | 15 | require 'amqp' 16 | 17 | # This example assumes you have configured RabbitMQ to listen on port 5671 18 | # for TLS connections (using RabbitMQ configuration file), for example: 19 | # 20 | # [ 21 | # {rabbit, [ 22 | # {ssl_listeners, [5671]}, 23 | # {ssl_options, [{cacertfile, "/usr/local/etc/rabbitmq/tls/testca/cacert.pem"}, 24 | # {certfile, "/usr/local/etc/rabbitmq/tls/server/cert.pem"}, 25 | # {keyfile, "/usr/local/etc/rabbitmq/tls/server/key.pem"}, 26 | # {verify, verify_peer}, 27 | # {fail_if_no_peer_cert, true}]} 28 | # ]} 29 | # ]. 30 | # 31 | # See TLS certificates under ./examples/tls_certificates 32 | 33 | AMQP.start(:port => 5671, 34 | :ssl => { 35 | :cert_chain_file => certificate_chain_file_path, 36 | :private_key_file => client_private_key_file_path 37 | }) do |connection| 38 | puts "Connected, authenticated. TLS seems to work." 39 | 40 | connection.disconnect { puts "Now closing the connection…"; EventMachine.stop } 41 | end 42 | -------------------------------------------------------------------------------- /examples/tls_certificates/client/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5DCCAcygAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xMTA0MTcyMDE4MzNaFw0xMjA0MTYyMDE4MzNaMCcxFDASBgNVBAMT 4 | C2dpb3ZlLmxvY2FsMQ8wDQYDVQQKEwZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUA 5 | A4IBDwAwggEKAoIBAQC/4CSqBjpmNXoDt5xU0D4ONG3bQXBV4bJid/nmzIvV67pb 6 | v/VpqKxM+UqoV9d09u/H+f/jAKu0of1e1d+1o09JtjJshX4sYREh2/n0umENH1xC 7 | yvWnP0eFTithj9qmVcK5UOvoZKSKYT4gtCIpYhRUQZkEhPYKhvxePztjRIeUghkK 8 | Qc9Qi0/eARm8d3Zdo0ORnnNNIP+G7BjecmJvTLCP/PBDIGG6r1eybNeulNWddgLg 9 | cUq0ACFepxCJW6RdGVrMXhWomScvKssIUMAdDfwM9ffq64MYE2ZLG1OBBPefNI47 10 | wz8h9ak15T2ZpKFU9biXLr/SnGhdhNR31d16pAtLAgMBAAGjLzAtMAkGA1UdEwQC 11 | MAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEB 12 | BQUAA4IBAQCVBpz3gZRr1s48SVF4+C9YLzrSaWsvzKZNDKH7RJ4f1VR//ZY5zsYi 13 | RqSlzSfLM76Y6Y/Eq0iFshtKmuXHKyA4r/Gp+iiCw4U9Htk91rg98wAPc8wOBgn1 14 | OmomH65JpLwxYvUwyt91opGppcqZHWhruhI0fFTFtPIlGKK3KOmJLPpaSvY0YTJ+ 15 | vaI3D6yQEMQoZ/mcXk928ofJJvOpUEmvjTW4Orz+T8NmiffLb64P50h86bdV+8tw 16 | FJx6ix6vLF41LU2iPEYHuuXkA7+M5e+POGscJJCb1p6JKxzI6D/UVDnrbhOlqBa5 17 | U45f0oXQ/ndOYUrBRu3BPFdNAjvpa0ld 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /examples/tls_certificates/client/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAv+AkqgY6ZjV6A7ecVNA+DjRt20FwVeGyYnf55syL1eu6W7/1 3 | aaisTPlKqFfXdPbvx/n/4wCrtKH9XtXftaNPSbYybIV+LGERIdv59LphDR9cQsr1 4 | pz9HhU4rYY/aplXCuVDr6GSkimE+ILQiKWIUVEGZBIT2Cob8Xj87Y0SHlIIZCkHP 5 | UItP3gEZvHd2XaNDkZ5zTSD/huwY3nJib0ywj/zwQyBhuq9XsmzXrpTVnXYC4HFK 6 | tAAhXqcQiVukXRlazF4VqJknLyrLCFDAHQ38DPX36uuDGBNmSxtTgQT3nzSOO8M/ 7 | IfWpNeU9maShVPW4ly6/0pxoXYTUd9XdeqQLSwIDAQABAoIBAQC1hScqcpns98pm 8 | md2bnyYV6iPDuTS9Crfnz/jrD7d6uXekNQXG33uhlnW6rN94F+TgGvKpnojSai14 9 | +nyZKdZotaUeZWvoMCw1DBZ8H5aRA4oU5k1f282dn0YLFjyT/64oAxYq1IuVHknY 10 | RpHK9K6mxygrzl21t94oi0lzr/FT29t8mSlcCQiHxAZWyGE55HvqSS4625P5pvh1 11 | Bh4bZGT285XvlA1qbKbEn8M1IsCZmhPU87U+k6lCvEpBG32cdg9Ykt+BA33OCJj0 12 | OrC6vKjLsIKEfbq8xoTjm7+fofv78B2/zobK7dFMVTAdnju8Tpwu/IDcHnLuKtt2 13 | Vd8GOwGBAoGBAPBO/EeHSvlT46F3jT8ygIhB2rGQ8LBZwQmiejOdfhJ5EPs8KC7U 14 | i9Wfo2Mktn7gr+X9nsY5ZHZoTFaFV1YSoIrsaWFd0RmuQKBcka+A9WPWEgRL0KrG 15 | Km9pHjlYK6WAu+XzKnGlHzasxxLW48mvuMQApE5U5nVbZWonGBA2psRNAoGBAMxn 16 | jHWH51SN5R/ldPvmNPEG8McR1XmzTM9M40snrj6UV8mLMH+KRHgoj664nhm1dnMa 17 | rolKzoFQtS5unwjCGX+Lx9AnwUDDak2Q6LsqedO0PhIwUEtcaLnt8Zf3KWi4v4Es 18 | eAHnYXZ1I7sqjCZ7pAwNBlCfE4Ai1XMH7syv5bn3AoGAYhbrlUrdSJ58eQkyp4w2 19 | uOegnABcrq9EQ2mF1hHAR0wRqWtpv4vUtFMgPzTaJToTsp5us9zza/2ww1RUTPb3 20 | fx12+l5wHrpo+MwwT2IlSCY2XniP6VVQNv/CbYfW8Qx2Jiu2tILBFfE6pS7/9fB7 21 | S84zQyIWm+q9n7HreZrFQbUCgYB4BnnY7eOtp+CaGS/XVrdRrOSn0FYNL3bz5080 22 | a2mKv6rI4x2oVrWb5R1x2GCl8gNK1akVX0LhdlXdnQFvsCIu3hKHrUByWg1K3MN8 23 | XBXLdXRZU9tiVTH9s7YAqRa8sndpT4Zsf8SgPWqs1fAUDNgoZ2GE59QYktvJvye/ 24 | M65uwwKBgDnuu0PZ6tn7dKZWYhfBeQT21DsaQglvY3kQ4RHHlHiQnyALKnZqbLu9 25 | wlAZIvRIltWeeQ+oT/Bxq9cD7GrdX8VmZ2xo/gYkJQoduT3AtyLrau8aZFWpiREH 26 | 2pDcznE7+DWcKKwr/Z2eQEOoE2KikeuAbMd2SG4vVTLG9w+N2e5I 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /examples/tls_certificates/client/keycert.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/examples/tls_certificates/client/keycert.p12 -------------------------------------------------------------------------------- /examples/tls_certificates/client/req.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICbDCCAVQCAQAwJzEUMBIGA1UEAxMLZ2lvdmUubG9jYWwxDzANBgNVBAoTBmNs 3 | aWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/gJKoGOmY1egO3 4 | nFTQPg40bdtBcFXhsmJ3+ebMi9Xrulu/9WmorEz5SqhX13T278f5/+MAq7Sh/V7V 5 | 37WjT0m2MmyFfixhESHb+fS6YQ0fXELK9ac/R4VOK2GP2qZVwrlQ6+hkpIphPiC0 6 | IiliFFRBmQSE9gqG/F4/O2NEh5SCGQpBz1CLT94BGbx3dl2jQ5Gec00g/4bsGN5y 7 | Ym9MsI/88EMgYbqvV7Js166U1Z12AuBxSrQAIV6nEIlbpF0ZWsxeFaiZJy8qywhQ 8 | wB0N/Az19+rrgxgTZksbU4EE9580jjvDPyH1qTXlPZmkoVT1uJcuv9KcaF2E1HfV 9 | 3XqkC0sCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4IBAQAOpwkzMe1xYgYz8GOp5xF7 10 | xJtfeh5z9JTt8ogvjS34mri2vNUPQd35H3y6Dhh9ZjLqC03mMV/KOtRCf7oJXpgZ 11 | S8C/NyJWNXB7/QNf9/EWEyOxoWYuvhTxqc0MhLPWrJRjgBKvvCGszBj2kWxDn7OO 12 | //TRq4ao2wQWHIlaP5htsr+rD4IJZqZC8lgptv0u9O/O8vruPUg3k6dnuiKdUyTL 13 | 2CDsiKSc6vZKJKL0TguBHSQj/sybAw1lyxIlpxiDcTCbM5FsER6jFydLly+ov3+x 14 | sqMOTieWU3qnaqOwK2ENqQfRMAk3FXEuDzvW4t7oxHB2gJfUJXfEVUWv7Kol25VT 15 | -----END CERTIFICATE REQUEST----- 16 | -------------------------------------------------------------------------------- /examples/tls_certificates/server/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5DCCAcygAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xMTA0MTcyMDE3MjdaFw0xMjA0MTYyMDE3MjdaMCcxFDASBgNVBAMT 4 | C2dpb3ZlLmxvY2FsMQ8wDQYDVQQKEwZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUA 5 | A4IBDwAwggEKAoIBAQDdBEpnl+BRcIzZ4M6pB649cT/YUxebTekUq0HhFXATba44 6 | XkSx81Nn5dMVnKgJgJVRhBxU0ZpBt4/wogKaaYI4/OAEgbUcH03OnEXHNLB586eJ 7 | GdaFHkSQOfnUbBIzpQKlQjGLfjmn6mXkLW5lLP5OrN+npuEI4Wq/jgbIQQp9t7Kw 8 | g+Pb9VdJGw0dmMlVfPP8FVCRpGB9lJc1Ayw8gKHg4mi/uyKKFdLV9IWf+DXlvRQ2 9 | vljmQEhSq4bvxnCtm4p5B7AFHefTnldSgGRUZuyI5/4vFMypB3deV+lku95514uN 10 | F0gg66eDAfoNjEmca09P+GBy8LfJsuiBeFV4irtjAgMBAAGjLzAtMAkGA1UdEwQC 11 | MAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEB 12 | BQUAA4IBAQCCmvsAQ1GaPfoKMqCWxyrQ2BNVPWm9J65thZKxZQF01gLox9cpv6+X 13 | QERcD71HStxbzh2B8Hebbk9OplGuyrdgfvzUxcn88kObj6udipDx4YxTJvtff/9w 14 | xeD5OWDVgef0GkB1Rjj3C3W/sfmTZBYfdKuWuwxMG/NxISkQP4aFHwJnPrzNx9ON 15 | bHoKVNrQ2iKAiMysjnFeA/4QuhBQRf41h9SBWwJEW3Ts91TzbgcjCL46Dq29QB9A 16 | 4v8t6K/nibP6n53zHbVzdxIEJ2hFKm+vuqaHRW3048Xgww1xkdxrVbyGp9si92i1 17 | KJ5SDIOR8bQ7OXvdvpiyy6p9fIG0Z6w0 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /examples/tls_certificates/server/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA3QRKZ5fgUXCM2eDOqQeuPXE/2FMXm03pFKtB4RVwE22uOF5E 3 | sfNTZ+XTFZyoCYCVUYQcVNGaQbeP8KICmmmCOPzgBIG1HB9NzpxFxzSwefOniRnW 4 | hR5EkDn51GwSM6UCpUIxi345p+pl5C1uZSz+Tqzfp6bhCOFqv44GyEEKfbeysIPj 5 | 2/VXSRsNHZjJVXzz/BVQkaRgfZSXNQMsPICh4OJov7siihXS1fSFn/g15b0UNr5Y 6 | 5kBIUquG78ZwrZuKeQewBR3n055XUoBkVGbsiOf+LxTMqQd3XlfpZLveedeLjRdI 7 | IOungwH6DYxJnGtPT/hgcvC3ybLogXhVeIq7YwIDAQABAoIBAEu0+YussZET/Ztw 8 | bznlQKEZVuZR6Ccxs+J5m1JvlnmBO4lheSR/lhVj2z9u7vx6SCupFk9TkQRrzWl/ 9 | BWdBNvMwY8gHajNc4bkhPKG1AbJ0bPIAoMPuj0vcICDMeBuqrVJQb0o6DaPgHdDg 10 | Yw1TMTVf8CiseC8jj/5XtykHZoGTNTKzusvTjL8hTXFaWQfHQaN3WC1qwrFU2+x6 11 | AJeoSz5F1Q/lykqVAdl2B1L39kiSCAkbVE1GI2qjftCff3ycufYV/fxXeyZwZx9B 12 | NGWUJFyZte8EcrAUoo9B/gvALGDbJsSUsbri+HsRsdOQT3K/giafUipX2FB8Bnxm 13 | nasEfskCgYEA74PrKYo13mTUWRJ2FQTBRHLsMR53PK83RpRRs8361/uCJrjpqfdD 14 | 2fUt8kH0rmm2vaWYsllucJoYdYSC9CQdECLzpOZS907PJHXCOsFsBjw74fvjZ+gY 15 | 9EXIENZSOSR1PQCWZm+5lL4xi/T+beWBfz0YksErj2GM7dyJeQjkIz8CgYEA7Dpx 16 | ANgrgO9WTu51NIlKt3P7+t6q6MHQcWuzkWMBmVU4zxeyggux+ucMj+l3KLyw7fLT 17 | jRz03eGpqjQT8Yl676uYONhTDC9VOBbLgjShuVOX7lleMLxVFJWqL1FphNghxysF 18 | HVCq1WH0Qu4keirPEotBxkNZRaRYHwRYlVPKMt0CgYEApIHSAj0IlNBiPS995R/X 19 | 8sCQU4heU1LxP0vd9gZy1OfNU/VLoE7RzqEkxrDgcu7u8cEMaOsd/L8KL6UtIKyx 20 | PYUUHV2I/I2nnp43Io35OSsj4ipU3eg/Q3+uU0oxPUg6MgT2SDNSnsQnWb6TBj5N 21 | PGxlNV7yIU/aMQF5dqVRtJcCgYEArC4Mn6jwTJImPnHgS+Kl6wFG8JvLxss9uu3d 22 | fGLFj5VmSsvi+Ja9qzstFNf+WlruOwF64KfycqdAmyZKQwsJ6BcSZJyIK6F0Y+V5 23 | f/YMyp/7ZWcOGEetW8uat9KHLqS6OglJOQzK96zl9MLPI5yAQevujSwZrYEUGcd5 24 | KZ5hCqECgYBExYSDJOuSMvKFw66jrLiBedLPuzh1iznwd6e4idpqIUkdhbEuXhHG 25 | +35HeN5cGwjbjXtIjxJsAddTbjvSqaPukmBKLm1ABqF3r0irbNaPcK1xfG9a5L28 26 | /enwipaSWjGovfDXWqmmCvWC8M7iGiqFChI87WlzbvaAapOW0D576Q== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /examples/tls_certificates/server/keycert.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/examples/tls_certificates/server/keycert.p12 -------------------------------------------------------------------------------- /examples/tls_certificates/server/req.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICbDCCAVQCAQAwJzEUMBIGA1UEAxMLZ2lvdmUubG9jYWwxDzANBgNVBAoTBnNl 3 | cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN0ESmeX4FFwjNng 4 | zqkHrj1xP9hTF5tN6RSrQeEVcBNtrjheRLHzU2fl0xWcqAmAlVGEHFTRmkG3j/Ci 5 | Apppgjj84ASBtRwfTc6cRcc0sHnzp4kZ1oUeRJA5+dRsEjOlAqVCMYt+OafqZeQt 6 | bmUs/k6s36em4Qjhar+OBshBCn23srCD49v1V0kbDR2YyVV88/wVUJGkYH2UlzUD 7 | LDyAoeDiaL+7IooV0tX0hZ/4NeW9FDa+WOZASFKrhu/GcK2binkHsAUd59OeV1KA 8 | ZFRm7Ijn/i8UzKkHd15X6WS73nnXi40XSCDrp4MB+g2MSZxrT0/4YHLwt8my6IF4 9 | VXiKu2MCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4IBAQC2aRbyq5pJ34M8jsaEjcks 10 | iov5KP17jfnHnz517/rKxKYRaoxftXVvUbtDLKMQNMAA9K65jetg6/6zqi3QTJwd 11 | 52Pn6OYTpzyFov42KRh1OSiRRa5CNXzDlHhosuVnVEOo2rdQggWZTY1clAbjEJmU 12 | N6bn6NSL4B/Vn8GAVxXhRGGoHj26LupdoI6GS2S3xuExw0xiS3usq6xYthpxHQ/L 13 | pQI2Ijk+IJZPnJR2RZji/7P3nWHWQX+HrCagCu4oyY4o7inWPVJpxD+1LmagRhv5 14 | RyMdQKoY+6x3/r+tWATTNOVqbGzfuKj6TQSkCYvOZOejlRBsMhyYlpldVMCRmaoh 15 | -----END CERTIFICATE REQUEST----- 16 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/cacert.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-amqp/amqp/5f3c7bab55cee73bbdcfdc438ee6f7c25061095c/examples/tls_certificates/testca/cacert.cer -------------------------------------------------------------------------------- /examples/tls_certificates/testca/cacert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICxjCCAa6gAwIBAgIJAOF/re9e0JhgMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV 3 | BAMTCE15VGVzdENBMB4XDTExMDQxNzIwMDcxN1oXDTEyMDQxNjIwMDcxN1owEzER 4 | MA8GA1UEAxMITXlUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB 5 | AQDK8ZdVo1llXXrS7ed5Luel1VRq0DmJG1TZ8bAgovK9fx6WsgzeJ17zYwAEheUz 6 | B8PogkNqU3ZIa4T51VCtamoiG6bbKYpco4lutKM7aNGNJNcUfDhwyt/NYOxXM3xf 7 | ahMWjrbH0e4qKJgEjnJLpoeEa+YquDG2NXzocZY5+upy0pX6Reh1EQbju69j9f5Q 8 | Z6u4cvraScyN5IYuq3lKTmc2TxVyINVkpK9DlGJZUBAOBLSbFxGZDRoY0D3b1aeS 9 | /XMfVvcrJi48Ns2ZvT+CAy0KVeKBeQ9+6kD/YAizcxDGLRvqOZXOHYaE2L51DabL 10 | QTxk9NFPgIxrYtGS7RtQ7dUhAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P 11 | BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAzFtKwsrCBaIAf1/VCJZh4+gzs/UW+ 12 | UXeC17GRzazb0O0drm9aMOtwE48NGVTwBjqmnPzFg56FYyll3oVZHz/fgkQZ+6iu 13 | qAbwlmY2H+L9RyC9Mv3B+Ew/o3MNCQQ3rgxbA7hb0k8mwDplxS5GBRROwZl/zHks 14 | gb4yPR6G83+zrgn6JIybdEGUySc1XDx+p6fVXvQG/1fsmExN9/ZuC6ulgBF7e+R5 15 | d7l1AluGL4kS7GMDRZnU9QcXkhnlUyPXIDr/Jd1HFKtwgrXtVl5YIWTaRdWOXGwX 16 | Q8BpM3Vk/NQFoTHO4Na3y8JY6iJzYTIXWHjI6RJdUffsEPtBoysHFHYv 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/certs/01.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5DCCAcygAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xMTA0MTcyMDE3MjdaFw0xMjA0MTYyMDE3MjdaMCcxFDASBgNVBAMT 4 | C2dpb3ZlLmxvY2FsMQ8wDQYDVQQKEwZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUA 5 | A4IBDwAwggEKAoIBAQDdBEpnl+BRcIzZ4M6pB649cT/YUxebTekUq0HhFXATba44 6 | XkSx81Nn5dMVnKgJgJVRhBxU0ZpBt4/wogKaaYI4/OAEgbUcH03OnEXHNLB586eJ 7 | GdaFHkSQOfnUbBIzpQKlQjGLfjmn6mXkLW5lLP5OrN+npuEI4Wq/jgbIQQp9t7Kw 8 | g+Pb9VdJGw0dmMlVfPP8FVCRpGB9lJc1Ayw8gKHg4mi/uyKKFdLV9IWf+DXlvRQ2 9 | vljmQEhSq4bvxnCtm4p5B7AFHefTnldSgGRUZuyI5/4vFMypB3deV+lku95514uN 10 | F0gg66eDAfoNjEmca09P+GBy8LfJsuiBeFV4irtjAgMBAAGjLzAtMAkGA1UdEwQC 11 | MAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEB 12 | BQUAA4IBAQCCmvsAQ1GaPfoKMqCWxyrQ2BNVPWm9J65thZKxZQF01gLox9cpv6+X 13 | QERcD71HStxbzh2B8Hebbk9OplGuyrdgfvzUxcn88kObj6udipDx4YxTJvtff/9w 14 | xeD5OWDVgef0GkB1Rjj3C3W/sfmTZBYfdKuWuwxMG/NxISkQP4aFHwJnPrzNx9ON 15 | bHoKVNrQ2iKAiMysjnFeA/4QuhBQRf41h9SBWwJEW3Ts91TzbgcjCL46Dq29QB9A 16 | 4v8t6K/nibP6n53zHbVzdxIEJ2hFKm+vuqaHRW3048Xgww1xkdxrVbyGp9si92i1 17 | KJ5SDIOR8bQ7OXvdvpiyy6p9fIG0Z6w0 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/certs/02.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5DCCAcygAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl 3 | c3RDQTAeFw0xMTA0MTcyMDE4MzNaFw0xMjA0MTYyMDE4MzNaMCcxFDASBgNVBAMT 4 | C2dpb3ZlLmxvY2FsMQ8wDQYDVQQKEwZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUA 5 | A4IBDwAwggEKAoIBAQC/4CSqBjpmNXoDt5xU0D4ONG3bQXBV4bJid/nmzIvV67pb 6 | v/VpqKxM+UqoV9d09u/H+f/jAKu0of1e1d+1o09JtjJshX4sYREh2/n0umENH1xC 7 | yvWnP0eFTithj9qmVcK5UOvoZKSKYT4gtCIpYhRUQZkEhPYKhvxePztjRIeUghkK 8 | Qc9Qi0/eARm8d3Zdo0ORnnNNIP+G7BjecmJvTLCP/PBDIGG6r1eybNeulNWddgLg 9 | cUq0ACFepxCJW6RdGVrMXhWomScvKssIUMAdDfwM9ffq64MYE2ZLG1OBBPefNI47 10 | wz8h9ak15T2ZpKFU9biXLr/SnGhdhNR31d16pAtLAgMBAAGjLzAtMAkGA1UdEwQC 11 | MAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEB 12 | BQUAA4IBAQCVBpz3gZRr1s48SVF4+C9YLzrSaWsvzKZNDKH7RJ4f1VR//ZY5zsYi 13 | RqSlzSfLM76Y6Y/Eq0iFshtKmuXHKyA4r/Gp+iiCw4U9Htk91rg98wAPc8wOBgn1 14 | OmomH65JpLwxYvUwyt91opGppcqZHWhruhI0fFTFtPIlGKK3KOmJLPpaSvY0YTJ+ 15 | vaI3D6yQEMQoZ/mcXk928ofJJvOpUEmvjTW4Orz+T8NmiffLb64P50h86bdV+8tw 16 | FJx6ix6vLF41LU2iPEYHuuXkA7+M5e+POGscJJCb1p6JKxzI6D/UVDnrbhOlqBa5 17 | U45f0oXQ/ndOYUrBRu3BPFdNAjvpa0ld 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/index.txt: -------------------------------------------------------------------------------- 1 | V 120416201727Z 01 unknown /CN=giove.local/O=server 2 | V 120416201833Z 02 unknown /CN=giove.local/O=client 3 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/index.txt.attr: -------------------------------------------------------------------------------- 1 | unique_subject = yes 2 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/index.txt.attr.old: -------------------------------------------------------------------------------- 1 | unique_subject = yes 2 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/index.txt.old: -------------------------------------------------------------------------------- 1 | V 120416201727Z 01 unknown /CN=giove.local/O=server 2 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/private/cakey.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAyvGXVaNZZV160u3neS7npdVUatA5iRtU2fGwIKLyvX8elrIM 3 | 3ide82MABIXlMwfD6IJDalN2SGuE+dVQrWpqIhum2ymKXKOJbrSjO2jRjSTXFHw4 4 | cMrfzWDsVzN8X2oTFo62x9HuKiiYBI5yS6aHhGvmKrgxtjV86HGWOfrqctKV+kXo 5 | dREG47uvY/X+UGeruHL62knMjeSGLqt5Sk5nNk8VciDVZKSvQ5RiWVAQDgS0mxcR 6 | mQ0aGNA929Wnkv1zH1b3KyYuPDbNmb0/ggMtClXigXkPfupA/2AIs3MQxi0b6jmV 7 | zh2GhNi+dQ2my0E8ZPTRT4CMa2LRku0bUO3VIQIDAQABAoIBAQDJoXiDHFVgUZ0L 8 | XlUBYKnEaIyDxzey0hXep7Me6eaUgW0JugLw4VsEI9NLqyBKMCfjpTCHvj6huzmV 9 | 4utSMI0cMC76Rm5ylgSgmhYnm3+/ZN/QOY71+YqcCfUmuj+SqNgoLEjLhPbEqipH 10 | NKO4J88ysOUwgmrZppDgfKIOHw66Xlx0WtyFksozLve5pqxzs2gNZDmT5YdlGt+w 11 | X2zaUr7GholPGUVzhZSlpBpPkloSNYyGPX7O25bc63Ev92m3vnroJZYFiaUaKcFE 12 | M2RVVd3m8J47uoSwxl2ppnIgwodTWe20swc3d4cXK30U4USLsvWesthnfUc65QWa 13 | KfeanOrBAoGBAOvxGM9ufV1EFyV3D4kDB2UGp2ccv2t+rJ+urpl7JLCw1Aetpc3v 14 | Qg/QsbBfOhfI650zOZgzE5bG6B6wNYVLAC/UusrYgeLkyqKVbQgDTP+djD61jYjy 15 | IG5RP7EumN07Gvja59B4Kw5zN6TB3MKGz9Qv3a2MOvyg/3TRnssHOkQ5AoGBANwy 16 | V822s149G46tIbESw5ICcY8HorP1kD2syMeBQWKJcEgiSXL8Q3TIKdqaim8Q1Bqu 17 | fSYwISUVsFDaTyvRl25hLfkQ0t+qsul7EcjNFHf9L7dJx7z/dj8lVTQWGYse5iVQ 18 | aplx7fYQHgXdC7NjtpIrxUZkJ7bAl+0cpavdcCgpAoGAetCbO46mDyBcdBIPsiAz 19 | fzEBfrkGIyxjKxPAqv/gz2CcXgrT3eiHGLhnZgmLscnSa5e4iTM9JSUQuri6g1HR 20 | HRS8zs34fmTd3deuU5d0QzJ9SD81F24B16rPXqmExNP5bER2mpuSvgjXlBmdklye 21 | XjM0TxxJsCsWDnb3E3QFrnECgYBSpXqbNZXBK0JqnMTmh1psNQqWWpFQ5jxLScza 22 | RMNbzqYcDPJwfAp9jJtY92Q6J6DUmuVSLgJivu88iZPpqHMj9MmikBP160XXqF+W 23 | dJLYLml4a/LSFzg0nziJojnYI7LSEorQKRjdoFMEdGDt5eEin9cdgn39c/ASCQyN 24 | o0FzcQKBgHifRoEEyyHzepXiv2osPsOV9cEoWROLRaooE7boPISimJ1PCFGON0XT 25 | 20PmWJL3j3/f2Eqk47x4WpzLOp/OwUqqpaDpImtQX7GD7C+/PbAdbT1Q1Kc9kxc9 26 | a5FJg85oJqDPB1yEmYG5nWIlqB3LOX/IdOfYSOUFvRiomwJJoxys 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/serial: -------------------------------------------------------------------------------- 1 | 03 2 | -------------------------------------------------------------------------------- /examples/tls_certificates/testca/serial.old: -------------------------------------------------------------------------------- 1 | 02 2 | -------------------------------------------------------------------------------- /gemfiles/eventmachine-pre: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | source :rubygems 4 | 5 | gem "eventmachine", "~> 1.0.0.beta.3" 6 | # gem "json", :platform => :ruby_18 7 | gem "amq-client", :git => "git://github.com/ruby-amqp/amq-client.git", :branch => "master" 8 | gem "amq-protocol", :git => "git://github.com/ruby-amqp/amq-protocol.git", :branch => "master" 9 | 10 | group :test do 11 | gem "rspec", "~> 2.6.0" 12 | gem "rake", "~> 0.9.2" 13 | 14 | gem "evented-spec", :git => "git://github.com/ruby-amqp/evented-spec.git", :branch => "master" 15 | gem "effin_utf8" 16 | 17 | gem "multi_json" 18 | 19 | gem "json", :platform => :jruby 20 | gem "yajl-ruby", :platform => :ruby_18 21 | end 22 | -------------------------------------------------------------------------------- /lib/amq/protocol/get_response.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | # Purpose of this class is to simplify work with GetOk and GetEmpty. 4 | module AMQ 5 | module Protocol 6 | class GetResponse 7 | attr_reader :method 8 | def initialize(method) 9 | @method = method 10 | end 11 | 12 | def empty? 13 | @method.is_a?(::AMQ::Protocol::Basic::GetEmpty) 14 | end 15 | 16 | # GetOk attributes 17 | def delivery_tag 18 | if @method.respond_to?(:delivery_tag) 19 | @method.delivery_tag 20 | end 21 | end 22 | 23 | def redelivered 24 | if @method.respond_to?(:redelivered) 25 | @method.redelivered 26 | end 27 | end 28 | 29 | def exchange 30 | if @method.respond_to?(:exchange) 31 | @method.exchange 32 | end 33 | end 34 | 35 | def routing_key 36 | if @method.respond_to?(:routing_key) 37 | @method.routing_key 38 | end 39 | end 40 | 41 | def message_count 42 | if @method.respond_to?(:message_count) 43 | @method.message_count 44 | end 45 | end 46 | 47 | # GetEmpty attributes 48 | def cluster_id 49 | if @method.respond_to?(:cluster_id) 50 | @method.cluster_id 51 | end 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/amqp/auth_mechanism_adapter.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module AMQP 4 | # Provides a flexible method for encoding AMQP credentials. PLAIN and 5 | # EXTERNAL are provided by this gem. In order to implement a new 6 | # authentication mechanism, create a subclass like so: 7 | # 8 | # class MyAuthMechanism < AMQP::Async::AuthMechanismAdapter 9 | # auth_mechanism "X-MYAUTH" 10 | # 11 | # def encode_credentials(username, password) 12 | # # ... 13 | # end 14 | # end 15 | class AuthMechanismAdapter 16 | 17 | # Find and instantiate an AuthMechanismAdapter. 18 | # 19 | # @param [Adapter] adapter The Adapter for which to encode credentials. 20 | # @return [AuthMechanismAdapter] An AuthMechanismAdapter that can encode 21 | # credentials for the Adapter. 22 | # @raise [NotImplementedError] The Adapter's mechanism does not 23 | # correspond to any known AuthMechanismAdapter. 24 | def self.for_adapter(adapter) 25 | registry[adapter.mechanism].new adapter 26 | end 27 | 28 | protected 29 | 30 | # Used by subclasses to declare the mechanisms that an 31 | # AuthMechanismAdapter understands. 32 | # 33 | # @param [Array] mechanisms One or more mechanisms that can be 34 | # handled by the subclass. 35 | def self.auth_mechanism(*mechanisms) 36 | mechanisms.each {|mechanism| registry[mechanism] = self} 37 | end 38 | 39 | private 40 | 41 | # Accesses the registry of AuthMechanismAdapter subclasses. Keys in 42 | # this hash are the names of the authentication mechanisms; values are 43 | # the classes that handle them. Referencing an unknown mechanism from 44 | # this Hash will raise NotImplementedError. 45 | def self.registry 46 | @@registry ||= Hash.new {raise NotImplementedError} 47 | end 48 | 49 | public 50 | 51 | # The Adapter that this AuthMechanismAdapter operates on behalf of. 52 | attr_reader :adapter 53 | 54 | private 55 | 56 | # Create a new AuthMechanismAdapter. Users of this class should instead 57 | # retrieve an instance through for_adapter. 58 | def initialize(adapter) 59 | @adapter = adapter 60 | end 61 | end 62 | end 63 | 64 | # pre-require builtin auth mechanisms 65 | Dir[File.join(File.dirname(__FILE__), 66 | File.basename(__FILE__, '.rb'), 67 | '*')].each do |f| 68 | require f 69 | end 70 | -------------------------------------------------------------------------------- /lib/amqp/auth_mechanism_adapter/external.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module AMQP 4 | 5 | # Manages the encoding of credentials for the EXTERNAL authentication 6 | # mechanism. 7 | class AuthMechanismAdapter::External < AuthMechanismAdapter 8 | 9 | auth_mechanism "EXTERNAL" 10 | 11 | # Encodes a username and password for the EXTERNAL mechanism. Since 12 | # authentication is handled by an encapsulating protocol like SSL or 13 | # UNIX domain sockets, EXTERNAL doesn't pass along any username or 14 | # password information at all and this method always returns the 15 | # empty string. 16 | # 17 | # @param [String] username The username to encode. This parameter is 18 | # ignored. 19 | # @param [String] password The password to encode. This parameter is 20 | # ignored. 21 | # @return [String] The username and password, encoded for the 22 | # EXTERNAL mechanism. This is always the empty string. 23 | def encode_credentials(username, password) 24 | "" 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/amqp/auth_mechanism_adapter/plain.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module AMQP 4 | 5 | # Manages the encoding of credentials for the PLAIN authentication 6 | # mechanism. 7 | class AuthMechanismAdapter::Plain < AuthMechanismAdapter 8 | 9 | auth_mechanism "PLAIN" 10 | 11 | # Encodes credentials for the given username and password. This 12 | # involves sending the password across the wire in plaintext, so 13 | # PLAIN authentication should only be used over a secure transport 14 | # layer. 15 | # 16 | # @param [String] username The username to encode. 17 | # @param [String] password The password to encode. 18 | # @return [String] The username and password, encoded for the PLAIN 19 | # mechanism. 20 | def encode_credentials(username, password) 21 | "\0#{username}\0#{password}" 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/amqp/bit_set.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "amq/bit_set" 4 | 5 | module AMQP 6 | # A forward reference for AMQP::BitSet that was extracted to amq-protocol 7 | # to make it possible to reuse it in Bunny. 8 | BitSet = AMQ::BitSet 9 | end # AMQP 10 | -------------------------------------------------------------------------------- /lib/amqp/broker.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module AMQP 4 | # A utility class that makes inspection of broker capabilities easier. 5 | class Broker 6 | 7 | # 8 | # API 9 | # 10 | 11 | RABBITMQ_PRODUCT = "RabbitMQ".freeze 12 | 13 | # Broker information 14 | # @return [Hash] 15 | # @see Session#server_properties 16 | attr_reader :properties 17 | 18 | # @return [Hash] properties Broker information 19 | # @see Session#server_properties 20 | def initialize(properties) 21 | @properties = properties 22 | end # initialize(properties) 23 | 24 | # @group Product information 25 | 26 | # @return [Boolean] true if broker is RabbitMQ 27 | def rabbitmq? 28 | self.product == RABBITMQ_PRODUCT 29 | end # rabbitmq? 30 | 31 | # @return [String] Broker product information 32 | def product 33 | @product ||= @properties["product"] 34 | end # product 35 | 36 | # @return [String] Broker version 37 | def version 38 | @version ||= @properties["version"] 39 | end # version 40 | 41 | # @endgroup 42 | 43 | 44 | 45 | # @group Product capabilities 46 | 47 | # @return [Boolean] 48 | def supports_publisher_confirmations? 49 | @properties["capabilities"]["publisher_confirms"] 50 | end # supports_publisher_confirmations? 51 | 52 | # @return [Boolean] 53 | def supports_basic_nack? 54 | @properties["capabilities"]["basic.nack"] 55 | end # supports_basic_nack? 56 | 57 | # @return [Boolean] 58 | def supports_consumer_cancel_notifications? 59 | @properties["capabilities"]["consumer_cancel_notify"] 60 | end # supports_consumer_cancel_notifications? 61 | 62 | # @return [Boolean] 63 | def supports_exchange_to_exchange_bindings? 64 | @properties["capabilities"]["exchange_exchange_bindings"] 65 | end # supports_exchange_to_exchange_bindings? 66 | 67 | 68 | # @endgroup 69 | 70 | 71 | end # Broker 72 | end # AMQP 73 | -------------------------------------------------------------------------------- /lib/amqp/callbacks.rb: -------------------------------------------------------------------------------- 1 | module AMQP 2 | module Callbacks 3 | 4 | def redefine_callback(event, callable = nil, &block) 5 | f = (callable || block) 6 | # yes, re-assign! 7 | @callbacks[event] = [f] 8 | 9 | self 10 | end 11 | 12 | def define_callback(event, callable = nil, &block) 13 | f = (callable || block) 14 | 15 | @callbacks[event] ||= [] 16 | @callbacks[event] << f if f 17 | 18 | self 19 | end # define_callback(event, &block) 20 | alias append_callback define_callback 21 | 22 | def prepend_callback(event, &block) 23 | @callbacks[event] ||= [] 24 | @callbacks[event].unshift(block) 25 | 26 | self 27 | end # prepend_callback(event, &block) 28 | 29 | def clear_callbacks(event) 30 | @callbacks[event].clear if @callbacks[event] 31 | end # clear_callbacks(event) 32 | 33 | 34 | def exec_callback(name, *args, &block) 35 | list = Array(@callbacks[name]) 36 | if list.any? 37 | list.each { |c| c.call(*args, &block) } 38 | end 39 | end 40 | 41 | def exec_callback_once(name, *args, &block) 42 | list = (@callbacks.delete(name) || Array.new) 43 | if list.any? 44 | list.each { |c| c.call(*args, &block) } 45 | end 46 | end 47 | 48 | def exec_callback_yielding_self(name, *args, &block) 49 | list = Array(@callbacks[name]) 50 | if list.any? 51 | list.each { |c| c.call(self, *args, &block) } 52 | end 53 | end 54 | 55 | def exec_callback_once_yielding_self(name, *args, &block) 56 | list = (@callbacks.delete(name) || Array.new) 57 | 58 | if list.any? 59 | list.each { |c| c.call(self, *args, &block) } 60 | end 61 | end 62 | 63 | def has_callback?(name) 64 | @callbacks[name] && !@callbacks[name].empty? 65 | end # has_callback? 66 | end # Callbacks 67 | end 68 | -------------------------------------------------------------------------------- /lib/amqp/channel_id_allocator.rb: -------------------------------------------------------------------------------- 1 | module AMQP 2 | module ChannelIdAllocator 3 | 4 | MAX_CHANNELS_PER_CONNECTION = (2**16) - 1 5 | 6 | def initialize(*args, &block) 7 | super 8 | 9 | @channel_id_mutex = Mutex.new 10 | end 11 | 12 | # Resets channel allocator. This method is thread safe. 13 | # @api public 14 | # @see Channel.next_channel_id 15 | # @see Channel.release_channel_id 16 | def reset_channel_id_allocator 17 | @channel_id_mutex.synchronize do 18 | int_allocator.reset 19 | end 20 | end 21 | 22 | # Releases previously allocated channel id. This method is thread safe. 23 | # 24 | # @param [Fixnum] Channel id to release 25 | # @api public 26 | # @see Channel.next_channel_id 27 | # @see Channel.reset_channel_id_allocator 28 | def release_channel_id(i) 29 | @channel_id_mutex.synchronize do 30 | int_allocator.release(i) 31 | end 32 | end 33 | 34 | # Returns next available channel id. This method is thread safe. 35 | # 36 | # @return [Fixnum] 37 | # @api public 38 | # @see Channel.release_channel_id 39 | # @see Channel.reset_channel_id_allocator 40 | def next_channel_id 41 | @channel_id_mutex.synchronize do 42 | result = int_allocator.allocate 43 | raise "No further channels available. Please open a new connection." if result < 0 44 | result 45 | end 46 | end 47 | 48 | private 49 | 50 | # @private 51 | def int_allocator 52 | # TODO: ideally, this should be in agreement with agreed max number of channels of the connection, 53 | # but it is possible that value either not yet available. MK. 54 | @int_allocator ||= IntAllocator.new(1, MAX_CHANNELS_PER_CONNECTION) 55 | end 56 | 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/amqp/compatibility/ruby187_patchlevel_check.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | if RUBY_VERSION =~ /^1.8.7/ 4 | require "rbconfig" 5 | conf = RbConfig::CONFIG 6 | 7 | # looks like PATCHLEVEL was added after 1.8.7-p249 release :( MK. 8 | if (conf["PATCHLEVEL"] && conf["PATCHLEVEL"] == "249") || (conf["libdir"] =~ /1.8.7-p249/) 9 | raise <<-MESSAGE 10 | IMPORTANT: amqp gem 0.8.0+ does not support Ruby 1.8.7-p249 (this exact patch level. p174, p334 and later patch levels are supported!) 11 | because of a nasty Ruby bug (http://bit.ly/iONBmH). Refer to http://groups.google.com/group/ruby-amqp/browse_thread/thread/37d6dcc1aea1c102 12 | for more information, especially if you want to verify whether a particular Ruby patch level or version or build suffers from 13 | this issue. 14 | 15 | To reiterate: 1.8.7-p174, p334 and later patch levels are supported, see http://travis-ci.org/ruby-amqp/amqp. The fix was committed to MRI in December 2009. It's 16 | a good idea to upgrade, although downgrading to p174 is an option, too. 17 | 18 | To learn more (including the 0.8.x migration guide) at http://bit.ly/rubyamqp and https://github.com/ruby-amqp. 19 | MESSAGE 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/amqp/consumer_tag_generator.rb: -------------------------------------------------------------------------------- 1 | module AMQP 2 | class ConsumerTagGenerator 3 | 4 | # 5 | # API 6 | # 7 | 8 | # @return [String] Generated consumer tag 9 | def generate 10 | "#{Kernel.rand}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}" 11 | end # generate 12 | 13 | # @return [String] Generated consumer tag 14 | def generate_for(queue) 15 | raise ArgumentError, "argument must respond to :name" unless queue.respond_to?(:name) 16 | 17 | "#{queue.name}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}" 18 | end # generate_for(queue) 19 | end # ConsumerTagGenerator 20 | end 21 | -------------------------------------------------------------------------------- /lib/amqp/deferrable.rb: -------------------------------------------------------------------------------- 1 | require "eventmachine" 2 | 3 | module AMQP 4 | Deferrable = EventMachine::DefaultDeferrable 5 | end 6 | -------------------------------------------------------------------------------- /lib/amqp/entity.rb: -------------------------------------------------------------------------------- 1 | require "amqp/openable" 2 | require "amqp/callbacks" 3 | 4 | module AMQP 5 | module RegisterEntityMixin 6 | # @example Registering Channel implementation 7 | # Adapter.register_entity(:channel, Channel) 8 | # # ... so then I can do: 9 | # channel = client.channel(1) 10 | # # instead of: 11 | # channel = Channel.new(client, 1) 12 | def register_entity(name, klass) 13 | define_method(name) do |*args, &block| 14 | klass.new(self, *args, &block) 15 | end # define_method 16 | end # register_entity 17 | end # RegisterEntityMixin 18 | 19 | module ProtocolMethodHandlers 20 | def handle(klass, &block) 21 | HandlersRegistry.register(klass, &block) 22 | end 23 | 24 | def handlers 25 | HandlersRegistry.handlers 26 | end 27 | end # ProtocolMethodHandlers 28 | 29 | 30 | # AMQ entities, as implemented by AMQP, have callbacks and can run them 31 | # when necessary. 32 | # 33 | # @note Exchanges and queues implementation is based on this class. 34 | # 35 | # @abstract 36 | module Entity 37 | 38 | # 39 | # Behaviors 40 | # 41 | 42 | include Openable 43 | include Callbacks 44 | 45 | # 46 | # API 47 | # 48 | 49 | # @return [Array<#call>] 50 | attr_reader :callbacks 51 | 52 | 53 | def initialize(connection) 54 | @connection = connection 55 | # Be careful with default values for #ruby hashes: h = Hash.new(Array.new); h[:key] ||= 1 56 | # won't assign anything to :key. MK. 57 | @callbacks = Hash.new 58 | end # initialize 59 | end # Entity 60 | 61 | # Common behavior of AMQ entities that can be either client or server-named, for example, exchanges and queues. 62 | module ServerNamedEntity 63 | 64 | # @return [Boolean] true if this entity is anonymous (server-named) 65 | def server_named? 66 | @server_named || @name.nil? || @name.empty? 67 | end 68 | # backwards compabitility. MK. 69 | alias anonymous? server_named? 70 | end # ServerNamedEntity 71 | end 72 | -------------------------------------------------------------------------------- /lib/amqp/extensions/rabbitmq.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | # No-op as of 1.1 4 | -------------------------------------------------------------------------------- /lib/amqp/framing/string/frame.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "amqp/exceptions" 4 | 5 | module AMQP 6 | module Framing 7 | module String 8 | class Frame < AMQ::Protocol::Frame 9 | ENCODINGS_SUPPORTED = defined? Encoding 10 | HEADER_SLICE = (0..6).freeze 11 | DATA_SLICE = (7..-1).freeze 12 | PAYLOAD_SLICE = (0..-2).freeze 13 | 14 | def self.decode(string) 15 | header = string[HEADER_SLICE] 16 | type, channel, size = self.decode_header(header) 17 | data = string[DATA_SLICE] 18 | payload = data[PAYLOAD_SLICE] 19 | frame_end = data[-1, 1] 20 | 21 | frame_end.force_encoding(AMQ::Protocol::Frame::FINAL_OCTET.encoding) if ENCODINGS_SUPPORTED 22 | 23 | # 1) the size is miscalculated 24 | if payload.bytesize != size 25 | raise BadLengthError.new(size, payload.bytesize) 26 | end 27 | 28 | # 2) the size is OK, but the string doesn't end with FINAL_OCTET 29 | raise NoFinalOctetError.new if frame_end != AMQ::Protocol::Frame::FINAL_OCTET 30 | 31 | self.new(type, payload, channel) 32 | end # self.from 33 | end # Frame 34 | end # String 35 | end # Framing 36 | end # AMQP 37 | -------------------------------------------------------------------------------- /lib/amqp/handlers_registry.rb: -------------------------------------------------------------------------------- 1 | module AMQP 2 | class HandlersRegistry 3 | 4 | @@handlers ||= Hash.new 5 | 6 | 7 | # 8 | # API 9 | # 10 | 11 | 12 | def self.register(klass, &block) 13 | @@handlers[klass] = block 14 | end 15 | class << self 16 | alias handle register 17 | end 18 | 19 | def self.find(klass) 20 | @@handlers[klass] 21 | end 22 | 23 | def self.handlers 24 | @@handlers 25 | end 26 | 27 | end # HandlersRegistry 28 | end 29 | -------------------------------------------------------------------------------- /lib/amqp/int_allocator.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "amq/int_allocator" 4 | 5 | module AMQP 6 | # A forward reference for AMQP::IntAllocator that was extracted to amq-protocol 7 | # to make it possible to reuse it in Bunny. 8 | IntAllocator = AMQ::IntAllocator 9 | end # AMQP 10 | -------------------------------------------------------------------------------- /lib/amqp/integration/rails.rb: -------------------------------------------------------------------------------- 1 | require "yaml" 2 | 3 | module AMQP 4 | module Integration 5 | class Rails 6 | 7 | def self.start(options_or_uri = {}, &block) 8 | yaml = YAML.load_file(File.join(::Rails.root, "config", "amqp.yml")) 9 | settings = yaml.fetch(::Rails.env, Hash.new).symbolize_keys 10 | 11 | arg = if options_or_uri.is_a?(Hash) 12 | settings.merge(options_or_uri)[:uri] 13 | else 14 | settings[:uri] || options_or_uri 15 | end 16 | 17 | EventMachine.next_tick do 18 | AMQP.start(arg, &block) 19 | end 20 | end 21 | end # Rails 22 | end # Integration 23 | end # AMQP 24 | -------------------------------------------------------------------------------- /lib/amqp/openable.rb: -------------------------------------------------------------------------------- 1 | module AMQP 2 | module Openable 3 | VALUES = [:opened, :closed, :opening, :closing].freeze 4 | 5 | class ImproperStatusError < ArgumentError 6 | def initialize(value) 7 | super("Value #{value.inspect} isn't permitted. Choose one of: #{AMQP::Openable::VALUES.inspect}") 8 | end 9 | end 10 | 11 | attr_reader :status 12 | def status=(value) 13 | if VALUES.include?(value) 14 | @status = value 15 | else 16 | raise ImproperStatusError.new(value) 17 | end 18 | end 19 | 20 | def opened? 21 | @status == :opened 22 | end 23 | alias open? opened? 24 | 25 | def closed? 26 | @status == :closed 27 | end 28 | 29 | 30 | 31 | def opening? 32 | @status == :opening 33 | end 34 | 35 | def closing? 36 | @status == :closing 37 | end 38 | 39 | 40 | def opened! 41 | @status = :opened 42 | end # opened! 43 | 44 | def closed! 45 | @status = :closed 46 | end # closed! 47 | 48 | 49 | 50 | def opening! 51 | @status = :opening 52 | end # opening! 53 | 54 | def closing! 55 | @status = :closing 56 | end # closing! 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/amqp/settings.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module AMQP 4 | module Settings 5 | CLIENT_PROPERTIES = { 6 | :platform => ::RUBY_DESCRIPTION, 7 | :product => "amqp gem", 8 | :information => "http://github.com/ruby-amqp/amqp", 9 | :version => AMQP::VERSION, 10 | :capabilities => { 11 | :publisher_confirms => true, 12 | :consumer_cancel_notify => true, 13 | :exchange_exchange_bindings => true, 14 | :"basic.nack" => true, 15 | :"connection.blocked" => true, 16 | :authentication_failure_close => true 17 | } 18 | } 19 | 20 | def self.client_properties 21 | @client_properties ||= CLIENT_PROPERTIES 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/amqp/version.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module AMQP 4 | # amqp gem version. Not to be confused with the AMQP protocol version 5 | # it implements. For that, see {AMQ::Protocol::VERSION} 6 | # 7 | # @see AMQ::Protocol::VERSION 8 | # @return [String] AMQP gem version 9 | VERSION = '1.9.0.pre' 10 | end 11 | -------------------------------------------------------------------------------- /repl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | bundle exec irb -Ilib -r'amqp' 4 | -------------------------------------------------------------------------------- /spec/integration/automatic_binding_for_default_direct_exchange_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "Queue that was bound to default direct exchange thanks to Automatic Mode (section 2.1.2.4 in AMQP 0.9.1 spec" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 3 14 | 15 | amqp_before do 16 | @channel = AMQP::Channel.new 17 | @channel.should be_open 18 | @channel.on_error do |ch, close| 19 | raise "Channel-level error!: #{close.inspect}" 20 | end 21 | 22 | @queue1 = @channel.queue("amqpgem.tests.integration.queue1", :auto_delete => true) 23 | @queue2 = @channel.queue("amqpgem.tests.integration.queue2", :auto_delete => true) 24 | 25 | # Rely on default direct exchange binding, see section 2.1.2.4 Automatic Mode in AMQP 0.9.1 spec. 26 | @exchange = AMQP::Exchange.default(@channel) 27 | end 28 | 29 | 30 | default_options AMQP_OPTS 31 | 32 | 33 | # 34 | # Examples 35 | # 36 | 37 | it "receives messages with routing key equals it's name" do 38 | @exchange.channel.should == @channel 39 | 40 | number_of_received_messages = 0 41 | expected_number_of_messages = 3 42 | dispatched_data = "to be received by queue1" 43 | 44 | @queue1.subscribe do |payload| 45 | number_of_received_messages += 1 46 | payload.should == dispatched_data 47 | end # subscribe 48 | 49 | 4.times do 50 | @exchange.publish("some white noise", :routing_key => "killa key") 51 | end 52 | 53 | expected_number_of_messages.times do 54 | @exchange.publish(dispatched_data, :routing_key => @queue1.name) 55 | end 56 | 57 | 4.times do 58 | @exchange.publish("some white noise", :routing_key => "killa key") 59 | end 60 | 61 | delayed(0.6) { 62 | # We never subscribe to it, hence, need to delete manually 63 | @queue2.delete 64 | } 65 | 66 | done(0.9) { 67 | number_of_received_messages.should == expected_number_of_messages 68 | } 69 | end # it 70 | end # describe 71 | -------------------------------------------------------------------------------- /spec/integration/automatic_recovery_predicate_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe AMQP::Channel, "#auto_recovery" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | include EventedSpec::SpecHelper 13 | 14 | 15 | default_options AMQP_OPTS 16 | default_timeout 2 17 | 18 | 19 | it "switches automatic recovery mode on" do 20 | ch = AMQP::Channel.new(AMQP.connection) 21 | ch.auto_recovery.should be_false 22 | ch.auto_recovery = true 23 | ch.auto_recovery.should be_true 24 | ch.auto_recovery = false 25 | ch.auto_recovery.should be_false 26 | 27 | done 28 | end 29 | end 30 | 31 | 32 | 33 | 34 | describe AMQP::Channel, "options hash" do 35 | 36 | # 37 | # Environment 38 | # 39 | 40 | include EventedSpec::AMQPSpec 41 | include EventedSpec::SpecHelper 42 | 43 | 44 | default_options AMQP_OPTS 45 | default_timeout 2 46 | 47 | 48 | it "can be passed as the 3rd constructor argument" do 49 | ch = AMQP::Channel.new(AMQP.connection, nil, :auto_recovery => true) 50 | ch.auto_recovery.should be_true 51 | ch.auto_recovery = false 52 | ch.auto_recovery.should be_false 53 | 54 | done 55 | end 56 | 57 | 58 | it "can be passed as the 2nd constructor argument" do 59 | ch = AMQP::Channel.new(AMQP.connection, :auto_recovery => true) 60 | ch.auto_recovery.should be_true 61 | ch.should be_auto_recovering 62 | ch.auto_recovery = false 63 | ch.auto_recovery.should be_false 64 | ch.should_not be_auto_recovering 65 | 66 | done 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/integration/basic_publish_with_message_framing_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "Large messages that need to be framed" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 10 14 | 15 | amqp_before do 16 | @channel = AMQP::Channel.new 17 | @channel.should be_open 18 | @channel.on_error do |ch, close| 19 | raise "Channel-level error!: #{close.inspect}" 20 | end 21 | 22 | @queue1 = @channel.queue("amqpgem.tests.integration.queue#{Time.now.to_i}#{rand}", :exclusive => true) 23 | @queue2 = @channel.queue("amqpgem.tests.integration.queue#{Time.now.to_i}#{rand}", :exclusive => true) 24 | 25 | # Rely on default direct exchange binding, see section 2.1.2.4 Automatic Mode in AMQP 0.9.1 spec. 26 | @exchange = AMQP::Exchange.default(@channel) 27 | end 28 | 29 | 30 | default_options AMQP_OPTS 31 | 32 | let(:body) { "мультибайт" * 1024 * 1024 } 33 | 34 | 35 | # 36 | # Examples 37 | # 38 | 39 | it "are framed correctly" do 40 | @exchange.channel.should == @channel 41 | 42 | number_of_received_messages = 0 43 | expected_number_of_messages = 3 44 | dispatched_data = "to be received by queue1" 45 | 46 | @queue1.subscribe do |payload| 47 | number_of_received_messages += 1 48 | payload.should == dispatched_data 49 | end # subscribe 50 | 51 | 4.times do 52 | @exchange.publish(body, :routing_key => "killa key") 53 | end 54 | 55 | expected_number_of_messages.times do 56 | @exchange.publish(dispatched_data, :routing_key => @queue1.name) 57 | end 58 | 59 | 4.times do 60 | @exchange.publish(body, :routing_key => "killa key") 61 | end 62 | 63 | delayed(0.6) { 64 | # We never subscribe to it, hence, need to delete manually 65 | @queue2.delete 66 | } 67 | 68 | done(5.0) { 69 | number_of_received_messages.should == expected_number_of_messages 70 | } 71 | end # it 72 | end # describe 73 | -------------------------------------------------------------------------------- /spec/integration/basic_return_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | 6 | describe "Message published as mandatory" do 7 | 8 | # 9 | # Environment 10 | # 11 | 12 | include EventedSpec::AMQPSpec 13 | include EventedSpec::SpecHelper 14 | 15 | em_before { AMQP.cleanup_state } 16 | em_after { AMQP.cleanup_state } 17 | 18 | default_options AMQP_OPTS 19 | default_timeout 3 20 | 21 | amqp_before do 22 | @channel = AMQP::Channel.new 23 | @channel.should be_open 24 | 25 | @exchange = @channel.fanout("amqpgem.specs.#{Time.now.to_i}", :auto_delete => true, :durable => false) 26 | end 27 | 28 | after(:all) do 29 | AMQP.cleanup_state 30 | done 31 | end 32 | 33 | 34 | context "that cannot be routed to any queue" do 35 | it "is returned to the publisher via basic.return" do 36 | returned_messages = [] 37 | 38 | @exchange.on_return do |basic_return, header, body| 39 | returned_messages << basic_return.reply_text 40 | end 41 | (1..10).to_a.each { |m| @exchange.publish(m, :mandatory => true) } 42 | 43 | done(1.0) { 44 | returned_messages.should == Array.new(10) { "NO_ROUTE" } 45 | } 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/integration/channel_close_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe AMQP::Channel, "#close(&callback)" do 6 | include EventedSpec::AMQPSpec 7 | 8 | it "takes a callback which will run when we get back Channel.Close-Ok" do 9 | @events = [] 10 | 11 | AMQP::Channel.new do |ch| 12 | @events << :open_ok 13 | ch.close do |channel, close_ok| 14 | @events << :close_ok 15 | end 16 | end 17 | 18 | done(0.3) { 19 | @events.should == [:open_ok, :close_ok] 20 | } 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/integration/channel_level_exception_handling_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "Channel-level exception" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 2 14 | 15 | amqp_before do 16 | @connection = AMQP.connect 17 | @channel = AMQP::Channel.new(@connection) 18 | end 19 | 20 | after(:all) do 21 | AMQP.cleanup_state 22 | done 23 | end 24 | 25 | 26 | # 27 | # Examples 28 | # 29 | 30 | it "can be handled with Channel#on_error" do 31 | @channel.on_error do |ch, channel_close| 32 | channel_close.method_id.should == 10 33 | channel_close.class_id.should == 50 34 | channel_close.reply_code.should == 406 35 | channel_close.reply_text.should_not be_nil 36 | channel_close.reply_text.should_not be_empty 37 | 38 | done 39 | end 40 | 41 | EventMachine.add_timer(0.4) do 42 | # these two definitions result in a race condition. For sake of this example, 43 | # however, it does not matter. Whatever definition succeeds first, 2nd one will 44 | # cause a channel-level exception (because attributes are not identical) 45 | # 46 | # 'a' * 80 makes queue name long enough for complete error message to be longer than 127 charachters. 47 | # makes it possible to detect signed vs unsigned integer issues in amq-protocol. MK. 48 | AMQP::Queue.new(@channel, "amqpgem.examples.channel_exception.#{'a' * 80}", :auto_delete => true, :durable => false) 49 | 50 | AMQP::Queue.new(@channel, "amqpgem.examples.channel_exception.#{'a' * 80}", :auto_delete => true, :durable => true) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/integration/channel_level_exception_with_multiple_channels_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe AMQP do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 5 14 | 15 | 16 | # 17 | # Examples 18 | # 19 | 20 | 21 | context "when queue is redeclared with different attributes across two channels" do 22 | let(:name) { "amqp-gem.nondurable.queue" } 23 | let(:options) { 24 | { :durable => false, :passive => false } 25 | } 26 | let(:different_options) { 27 | { :durable => true, :passive => false } 28 | } 29 | 30 | 31 | it "should trigger channel-level #on_error callback" do 32 | @channel = AMQP::Channel.new 33 | @channel.on_error do |ch, close| 34 | puts "This should never happen" 35 | end 36 | @q1 = @channel.queue(name, options) 37 | 38 | # Small delays to ensure the order of execution 39 | delayed(0.1) { 40 | @other_channel = AMQP::Channel.new 41 | @other_channel.on_error do |ch, close| 42 | @callback_fired = true 43 | end 44 | puts "other_channel.id = #{@other_channel.id}" 45 | @q2 = @other_channel.queue(name, different_options) 46 | } 47 | 48 | delayed(0.3) { 49 | @q2.delete 50 | } 51 | 52 | done(0.4) { 53 | @callback_fired.should be_true 54 | # looks like there is a difference between platforms/machines 55 | # so check either one. MK. 56 | @other_channel.closed?.should be_true 57 | } 58 | end 59 | end 60 | end # describe AMQP 61 | -------------------------------------------------------------------------------- /spec/integration/connection_close_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe AMQP::Session, "#close(&callback)" do 6 | include EventedSpec::AMQPSpec 7 | 8 | it "takes a callback which will run when we get back connection.close-ok" do 9 | @events = [] 10 | 11 | c = AMQP.connect do |session| 12 | @events << :open_ok 13 | session.close do |session, close_ok| 14 | @events << :close_ok 15 | end 16 | end 17 | 18 | done(0.3) { 19 | c.should be_closed 20 | @events.should == [:open_ok, :close_ok] 21 | } 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/integration/connection_level_exception_handling_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "Connection-level exception" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 2 14 | 15 | amqp_before do 16 | @connection = AMQP.connect 17 | @channel = AMQP::Channel.new(@connection) 18 | end 19 | 20 | after(:all) do 21 | AMQP.cleanup_state 22 | done 23 | end 24 | 25 | 26 | # 27 | # Examples 28 | # 29 | 30 | it "can be handled with Session#on_error" do 31 | @connection.on_error do |conn, connection_close| 32 | conn.should == @connection 33 | 34 | connection_close.method_id.should == 31 35 | connection_close.class_id.should == 10 36 | connection_close.reply_code.should == 504 37 | connection_close.reply_text.should_not be_nil 38 | connection_close.reply_text.should_not be_empty 39 | 40 | done 41 | end 42 | 43 | EventMachine.add_timer(0.3) do 44 | # send_frame is NOT part of the public API, but it is public for entities like AMQ::Client::Channel 45 | # and we use it here to trigger a connection-level exception. MK. 46 | @connection.send_frame(AMQ::Protocol::Connection::TuneOk.encode(1000, 1024 * 128 * 1024, 10)) 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/integration/declare_and_immediately_bind_a_server_named_queue_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "Server-named", AMQP::Queue do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 2 14 | 15 | 16 | # 17 | # Examples 18 | # 19 | 20 | 21 | context "bound to a pre-defined exchange" do 22 | it "delays binding until after queue.declare-ok arrives" do 23 | mailbox = [] 24 | channel = AMQP::Channel.new 25 | exchange = channel.fanout("amq.fanout") 26 | input = "Independencia de resolución, ¿una realidad en Mac OS X Lion?" 27 | 28 | channel.queue("", :auto_delete => true).bind(exchange).subscribe do |header, body| 29 | mailbox << body 30 | end 31 | 32 | delayed(0.5) { 33 | exchange.publish(input) 34 | } 35 | 36 | done(1.0) { 37 | mailbox.size.should == 1 38 | } 39 | end 40 | end 41 | 42 | 43 | context "bound to a pre-defined exchange" do 44 | it "delays binding until after queue.declare-ok arrives" do 45 | mailbox = [] 46 | channel = AMQP::Channel.new 47 | exchange = channel.fanout("amqpgem.examples.exchanges.fanout", :durable => false) 48 | input = "Just send me already" 49 | 50 | channel.queue("", :auto_delete => true).bind(exchange).subscribe do |header, body| 51 | mailbox << body 52 | end 53 | 54 | delayed(0.5) { 55 | exchange.publish(input) 56 | } 57 | 58 | done(1.0) { 59 | mailbox.size.should == 1 60 | } 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/integration/declare_one_hundred_server_named_queues_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "Server-named", AMQP::Queue do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 5 14 | 15 | amqp_before do 16 | @channel = AMQP::Channel.new 17 | end 18 | 19 | 20 | # 21 | # Examples 22 | # 23 | 24 | 25 | it "can be declared en masse" do 26 | n = 100 27 | queues = [] 28 | 29 | n.times do 30 | queues << @channel.queue("", :auto_delete => true) 31 | end 32 | 33 | done(2.5) { 34 | queues.size.should == n 35 | # this is RabbitMQ-specific. But it is OK for now. MK. 36 | queues.all? { |q| q.name =~ /^amq.*/ }.should be_true 37 | 38 | # no duplicates. MK. 39 | names = queues.map { |q| q.name } 40 | names.uniq.size.should == n 41 | names.uniq.should == names 42 | } 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/integration/fanout_exchange_routing_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe AMQP::Exchange, "of type fanout" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | include EventedSpec::SpecHelper 13 | 14 | em_before { AMQP.cleanup_state } 15 | em_after { AMQP.cleanup_state } 16 | 17 | default_options AMQP_OPTS 18 | default_timeout 6 19 | 20 | amqp_before do 21 | @channel = AMQP::Channel.new 22 | @channel.should be_open 23 | end 24 | 25 | after(:all) do 26 | AMQP.cleanup_state 27 | done 28 | end 29 | 30 | 31 | # 32 | # Examples 33 | # 34 | 35 | 36 | context "with three bound queues" do 37 | it "routes all messages to all bound queues" do 38 | @exchange = @channel.fanout("amqpgem.integration.multicast.fanout", :auto_delete => true) 39 | @queue1 = @channel.queue("amqpgem.integration.multicast.queue1", :auto_delete => true) 40 | @queue2 = @channel.queue("amqpgem.integration.multicast.queue2", :auto_delete => true) 41 | @queue3 = @channel.queue("amqpgem.integration.multicast.queue3", :auto_delete => true) 42 | 43 | @queues = [@queue1, @queue2, @queue3] 44 | 45 | @received_messages = { 46 | @queue1.name => [], 47 | @queue2.name => [], 48 | @queue3.name => [] 49 | } 50 | 51 | @expected_number_of_messages = { 52 | @queue1.name => 10, 53 | @queue2.name => 10, 54 | @queue3.name => 10 55 | } 56 | 57 | 58 | @sent_values = Array.new 59 | 60 | @queue1.bind(@exchange).subscribe do |payload| 61 | @received_messages[@queue1.name].push(payload.to_i) 62 | end # subscribe 63 | 64 | @queue2.bind(@exchange).subscribe do |payload| 65 | @received_messages[@queue2.name].push(payload.to_i) 66 | end # subscribe 67 | 68 | @queue3.bind(@exchange).subscribe do |payload| 69 | @received_messages[@queue3.name].push(payload.to_i) 70 | end # subscribe 71 | 72 | 10.times do 73 | dispatched_data = rand(5_000_000) 74 | @sent_values.push(dispatched_data) 75 | 76 | @exchange.publish(dispatched_data, :mandatory => false) 77 | end 78 | 79 | # for Rubinius, it is surprisingly slow on this workload 80 | done(1.5) { 81 | [@queue1, @queue2, @queue3].each do |q| 82 | @received_messages[q.name].size.should == @expected_number_of_messages[q.name] 83 | 84 | # this one is ordering assertion 85 | @received_messages[q.name].should == @sent_values 86 | end 87 | } 88 | end # it 89 | end 90 | end # describe 91 | -------------------------------------------------------------------------------- /spec/integration/hello_world_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe "A 'Hello, world'-like example with a non-empty message" 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 => "messages.all") 25 | end 26 | 27 | 28 | 29 | it "is delivered" do 30 | consumer1 = AMQP::Consumer.new(@channel, @queue).consume 31 | consumer1.on_delivery do |metadata, payload| 32 | done 33 | end 34 | 35 | EventMachine.add_timer(0.5) do 36 | @exchange.publish("Hello!", :routing_key => "messages.all") 37 | end 38 | end 39 | end 40 | 41 | 42 | 43 | describe "A 'Hello, world'-like example with a blank message" do 44 | 45 | # 46 | # Environment 47 | # 48 | 49 | include EventedSpec::AMQPSpec 50 | default_options AMQP_OPTS 51 | default_timeout 5 52 | 53 | amqp_before do 54 | @channel = AMQP::Channel.new 55 | @channel.on_error do |ch, close| 56 | raise "Channel-level error!: #{close.inspect}" 57 | end 58 | 59 | @queue = @channel.queue("", :auto_delete => true) 60 | @exchange = @channel.direct("amqpgem.tests.integration.direct.exchange", :auto_delete => true) 61 | 62 | @queue.bind(@exchange, :routing_key => "messages.all") 63 | end 64 | 65 | 66 | 67 | it "is delivered" do 68 | consumer1 = AMQP::Consumer.new(@channel, @queue).consume 69 | consumer1.on_delivery do |metadata, payload| 70 | done 71 | end 72 | 73 | EventMachine.add_timer(0.5) do 74 | @exchange.publish("", :routing_key => "messages.all") 75 | end 76 | end 77 | end -------------------------------------------------------------------------------- /spec/integration/mandatory_messages_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'spec_helper' 3 | 4 | 5 | describe "When exchange a message is published to has no bindings" 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 | context "and message is published as :mandatory" do 27 | it "that message is returned to the publisher" do 28 | exchange = @producer_channel.fanout("amqpgem.examples.mandatory.messages", :auto_delete => true) 29 | 30 | exchange.on_return do |basic_return, metadata, payload| 31 | done if payload == "mandatory message body" 32 | end 33 | 34 | exchange.publish "mandatory message body", :mandatory => true 35 | end 36 | end 37 | 38 | 39 | 40 | context "and message is published as non :mandatory" do 41 | it "that message is dropped" do 42 | exchange = @producer_channel.fanout("amqpgem.examples.mandatory.messages", :auto_delete => true) 43 | 44 | exchange.on_return do |basic_return, metadata, payload| 45 | fail "Should not happen" 46 | end 47 | exchange.publish "mandatory message body", :mandatory => false 48 | 49 | done(1.0) 50 | end 51 | end 52 | end # describe 53 | -------------------------------------------------------------------------------- /spec/integration/message_acknowledgement_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | unless ENV["CI"] 6 | describe "Message acknowledgements" do 7 | 8 | # 9 | # Environment 10 | # 11 | 12 | include EventedSpec::AMQPSpec 13 | 14 | default_timeout 120 15 | 16 | amqp_before do 17 | @connection = AMQP.connect 18 | @channel1 = AMQP::Channel.new(@connection) 19 | @channel2 = AMQP::Channel.new(@connection) 20 | end 21 | 22 | 23 | it "can be issued for delivery tags >= 192" do 24 | exchange_name = "amqpgem.tests.fanout#{rand}" 25 | queue = @channel1.queue("", :auto_delete => true).bind(exchange_name).subscribe(:ack => true) do |metadata, payload| 26 | puts "x-sequence = #{metadata.headers['x-sequence']}, delivery_tag = #{metadata.delivery_tag}" if ENV["DEBUG"] 27 | metadata.ack 28 | if metadata.delivery_tag >= 999 29 | done(1.0) 30 | end 31 | end 32 | 33 | exchange = @channel2.fanout(exchange_name, :durable => false) 34 | 2000.times do |i| 35 | exchange.publish("", :headers => { 'x-sequence' => i }) 36 | end 37 | end 38 | end 39 | end -------------------------------------------------------------------------------- /spec/integration/ordering_of_published_messages_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "100 AMQP messages" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | default_options AMQP_OPTS 13 | default_timeout 5 14 | 15 | 16 | before :all do 17 | @list = Range.new(0, 100, true).to_a 18 | end 19 | 20 | 21 | context "published and received on the same channel" do 22 | amqp_before do 23 | @channel = AMQP::Channel.new 24 | @channel.on_error do |ch, close| 25 | raise "Channel-level error!: #{close.inspect}" 26 | end 27 | 28 | @queue = @channel.queue("amqpgem.tests.integration.queue1", :auto_delete => true) 29 | end 30 | 31 | # 32 | # Examples 33 | # 34 | 35 | it "are received on the same channel in the order of publishing" do 36 | received = [] 37 | 38 | @queue.subscribe do |metadata, payload| 39 | received << payload.to_i 40 | end 41 | 42 | EventMachine.add_timer(0.3) do 43 | @list.each { |i| @channel.default_exchange.publish(i.to_s, :routing_key => @queue.name) } 44 | end 45 | 46 | done(3.5) { 47 | received.size.should == 100 48 | received.first.should == 0 49 | received.last.should == 99 50 | 51 | received.should == @list 52 | } 53 | end 54 | end 55 | 56 | 57 | context "published on two different channels" do 58 | amqp_before do 59 | @channel1 = AMQP::Channel.new 60 | @channel2 = AMQP::Channel.new 61 | 62 | @channel1.on_error do |ch, close| 63 | raise "Channel-level error!: #{close.inspect}" 64 | end 65 | @channel2.on_error do |ch, close| 66 | raise "Channel-level error!: #{close.inspect}" 67 | end 68 | 69 | @queue = @channel1.queue("amqpgem.tests.integration.queue1", :auto_delete => true) 70 | end 71 | 72 | # 73 | # Examples 74 | # 75 | 76 | it "are received on the same channel in the order of publishing" do 77 | received = [] 78 | 79 | @queue.subscribe do |metadata, payload| 80 | received << payload.to_i 81 | end 82 | 83 | EventMachine.add_timer(0.3) do 84 | @list.each { |i| @channel2.default_exchange.publish(i.to_s, :routing_key => @queue.name) } 85 | end 86 | 87 | done(3.5) { 88 | received.size.should == 100 89 | received.first.should == 0 90 | received.last.should == 99 91 | 92 | received.should == @list 93 | } 94 | end 95 | end 96 | end # describe 97 | -------------------------------------------------------------------------------- /spec/integration/queue_exclusivity_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "Non-exclusive queue" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::EMSpec 12 | 13 | default_timeout 5 14 | 15 | em_after { @connection1.close; @connection2.close } 16 | # 17 | # Examples 18 | # 19 | 20 | it "can be used across multiple connections" do 21 | @connection1 = AMQP.connect do 22 | @connection2 = AMQP.connect do 23 | @connection1.should_not == @connection2 24 | 25 | channel1 = AMQP::Channel.new(@connection1) 26 | channel2 = AMQP::Channel.new(@connection2) 27 | 28 | instance1 = AMQP::Queue.new(channel1, "amqpgem.integration.queues.non-exclusive", :exclusive => false, :auto_delete => true) 29 | instance2 = AMQP::Queue.new(channel2, "amqpgem.integration.queues.non-exclusive", :exclusive => false, :auto_delete => true) 30 | 31 | exchange1 = channel1.fanout("amqpgem.integration.exchanges.fanout1", :auto_delete => true) 32 | exchange2 = channel2.fanout("amqpgem.integration.exchanges.fanout2", :auto_delete => true) 33 | 34 | 35 | instance1.bind(exchange1).subscribe do |payload| 36 | end 37 | 38 | instance2.bind(exchange2).subscribe do |payload| 39 | end 40 | 41 | done(0.2) { 42 | channel1.should be_open 43 | channel1.close 44 | 45 | channel2.should be_open 46 | channel2.close 47 | } 48 | end 49 | end 50 | end 51 | end 52 | 53 | 54 | 55 | describe "Exclusive queue" do 56 | 57 | # 58 | # Environment 59 | # 60 | 61 | include EventedSpec::EMSpec 62 | 63 | default_timeout 2 64 | 65 | em_after { @connection1.close; @connection2.close } 66 | 67 | 68 | # 69 | # Examples 70 | # 71 | 72 | it "can ONLY be used by ONE connection" do 73 | @connection1 = AMQP.connect do 74 | @connection2 = AMQP.connect do 75 | @connection1.should_not == @connection2 76 | 77 | queue_name = "amqpgem.integration.queues.exclusive" 78 | callback_fired = false 79 | @channel1 = AMQP::Channel.new(@connection1) do 80 | AMQP::Queue.new(@channel1, queue_name, :exclusive => true) do 81 | @channel2 = AMQP::Channel.new(@connection2) do 82 | AMQP::Queue.new(@channel2, queue_name, :exclusive => true) do 83 | callback_fired = true 84 | end 85 | end 86 | end 87 | end 88 | 89 | done(1) { 90 | callback_fired.should be_false 91 | @channel1.should_not be_closed 92 | # because it is a channel-level exception 93 | @channel2.should be_closed 94 | } 95 | end 96 | end 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /spec/integration/queue_redeclaration_with_incompatible_attributes_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "AMQP queue redeclaration with different attributes" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 5 14 | 15 | 16 | # 17 | # Examples 18 | # 19 | 20 | context "when :durable value is different" do 21 | let(:name) { "amqp-gem.nondurable.queue" } 22 | let(:options) { 23 | { :durable => false, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false } 24 | } 25 | let(:different_options) { 26 | { :durable => true, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false} 27 | } 28 | 29 | 30 | it "should raise AMQP::IncompatibleOptionsError for incompatable options" do 31 | channel = AMQP::Channel.new 32 | channel.on_error do |ch, channel_close| 33 | @error_code = channel_close.reply_code 34 | end 35 | 36 | channel.queue(name, options) 37 | expect { 38 | channel.queue(name, different_options) 39 | }.to raise_error 40 | 41 | done(0.5) { 42 | @error_code.should == 406 43 | } 44 | end 45 | end 46 | 47 | context "when :headers are different" do 48 | let(:name) { "amqp-gem.nondurable.queue" } 49 | let(:options) { 50 | { :durable => false, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false } 51 | } 52 | let(:different_options) { 53 | { :durable => false, :exclusive => true, :auto_delete => true, :arguments => {}, :passive => false, :header => {:random => 'stuff' } } 54 | } 55 | 56 | it "should not raise AMQP::IncompatibleOptionsError for irrelevant options" do 57 | channel = AMQP::Channel.new 58 | channel.on_error do |ch, channel_close| 59 | @error_code = channel_close.reply_code 60 | end 61 | 62 | channel.queue(name, options) 63 | expect { 64 | channel.queue(name, different_options) 65 | }.to_not raise_error 66 | 67 | done(0.5) { 68 | @error_code.should == 406 69 | } 70 | end 71 | end 72 | end # describe AMQP 73 | -------------------------------------------------------------------------------- /spec/integration/queue_status_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe AMQP::Queue do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 5 14 | 15 | 16 | 17 | # 18 | # Examples 19 | # 20 | 21 | describe "#status" do 22 | it "yields # of messages & consumers to the callback" do 23 | events = [] 24 | channel = AMQP::Channel.new 25 | 26 | queue1 = channel.queue("", :auto_delete => true) 27 | queue2 = channel.queue("amqpgem.tests.a.named.queue", :auto_delete => true) 28 | 29 | EventMachine.add_timer(1.0) do 30 | queue1.status do |m, c| 31 | events << :queue1_declare_ok 32 | end 33 | queue2.status do |m, c| 34 | events << :queue2_declare_ok 35 | end 36 | end 37 | 38 | done(2.0) { 39 | events.should include(:queue1_declare_ok) 40 | events.should include(:queue2_declare_ok) 41 | } 42 | end 43 | 44 | 45 | it "yields # of messages & consumers to the callback in pseudo-synchronous code" do 46 | events = [] 47 | channel = AMQP::Channel.new 48 | 49 | queue1 = channel.queue("", :auto_delete => true) 50 | queue2 = channel.queue("amqpgem.tests.a.named.queue", :auto_delete => true) 51 | 52 | queue1.status do |m, c| 53 | events << :queue1_declare_ok 54 | end 55 | queue2.status do |m, c| 56 | events << :queue2_declare_ok 57 | end 58 | 59 | done(2.0) { 60 | queue1.name.should =~ /^amq\..+/ 61 | events.should include(:queue1_declare_ok) 62 | events.should include(:queue2_declare_ok) 63 | } 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/integration/recovery/per_channel_automatic_recovery_on_graceful_broker_shutdown_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'spec_helper' 3 | 4 | unless ENV["CI"] 5 | describe "Per-channel automatic channel recovery" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include RabbitMQ::Control 12 | 13 | include EventedSpec::AMQPSpec 14 | default_timeout 20.0 15 | 16 | amqp_before do 17 | @channel = AMQP::Channel.new(AMQP.connection, :auto_recovery => true) 18 | end 19 | 20 | 21 | after :all do 22 | start_rabbitmq unless rabbitmq_pid 23 | end 24 | 25 | # ... 26 | 27 | 28 | # 29 | # Examples 30 | # 31 | 32 | it "can be used when broker is shut down gracefully" do 33 | AMQP.connection.on_error do |conn, connection_close| 34 | puts "[connection.close] Reply code = #{connection_close.reply_code}, reply text = #{connection_close.reply_text}" 35 | if connection_close.reply_code == 320 36 | puts "[connection.close] Setting up a periodic reconnection timer..." 37 | conn.periodically_reconnect(1) 38 | end 39 | end 40 | 41 | pid = rabbitmq_pid 42 | puts "rabbitmq pid = #{pid.inspect}" 43 | 44 | stop_rabbitmq 45 | rabbitmq_pid.should be_nil 46 | 47 | # 2 seconds later, check that we are reconnecting 48 | EventMachine.add_timer(2.0) do 49 | AMQP.connection.should_not be_connected 50 | AMQP.connection.should be_reconnecting 51 | end 52 | 53 | 54 | # 4 seconds later, start RabbitMQ 55 | EventMachine.add_timer(4.0) do 56 | start_rabbitmq 57 | rabbitmq_pid.should_not be_nil 58 | end 59 | 60 | # 10 seconds later, use the (now recovered) connection. Note that depending 61 | # on # of plugins used it may take 5-10 seconds to start up RabbitMQ and initialize it, 62 | # then open a new AMQP connection. That's why we wait. MK. 63 | EventMachine.add_timer(10.0) do 64 | AMQP.connection.should be_connected 65 | AMQP.connection.should_not be_reconnecting 66 | 67 | @channel.queue("amqpgem.tests.a.queue", :auto_delete => true).subscribe do |metadata, payload| 68 | puts "Got a message: #{payload.inspect}" 69 | done 70 | end 71 | 72 | EventMachine.add_timer(1.5) { @channel.default_exchange.publish("", :routing_key => "amqpgem.tests.a.queue") } 73 | end 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/integration/recovery/per_channel_automatic_recovery_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'spec_helper' 3 | 4 | unless ENV["CI"] 5 | describe "Per-channel automatic channel recovery" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include RabbitMQ::Control 12 | 13 | include EventedSpec::AMQPSpec 14 | default_timeout 20.0 15 | 16 | amqp_before do 17 | @channel = AMQP::Channel.new(AMQP.connection, :auto_recovery => true) 18 | end 19 | 20 | after :all do 21 | start_rabbitmq unless rabbitmq_pid 22 | end 23 | 24 | # ... 25 | 26 | 27 | # 28 | # Examples 29 | # 30 | 31 | it "kicks in when broker goes down" do 32 | AMQP.connection.on_tcp_connection_loss do |conn, settings| 33 | puts "[network failure] Trying to reconnect..." 34 | conn.reconnect(false, 1) 35 | end 36 | 37 | pid = rabbitmq_pid 38 | puts "rabbitmq pid = #{pid.inspect}" 39 | 40 | kill_rabbitmq 41 | rabbitmq_pid.should be_nil 42 | 43 | # 2 seconds later, check that we are reconnecting 44 | EventMachine.add_timer(2.0) do 45 | AMQP.connection.should_not be_connected 46 | AMQP.connection.should be_reconnecting 47 | end 48 | 49 | 50 | # 4 seconds later, start RabbitMQ 51 | EventMachine.add_timer(4.0) do 52 | start_rabbitmq 53 | rabbitmq_pid.should_not be_nil 54 | end 55 | 56 | # 12 seconds later, use the (now recovered) connection. Note that depending 57 | # on # of plugins used it may take 5-10 seconds to start up RabbitMQ and initialize it, 58 | # then open a new AMQP connection. That's why we wait. MK. 59 | EventMachine.add_timer(12.0) do 60 | AMQP.connection.should be_connected 61 | AMQP.connection.should_not be_reconnecting 62 | 63 | @channel.queue("amqpgem.tests.a.queue", :auto_delete => true).subscribe do |metadata, payload| 64 | puts "Got a message" 65 | done 66 | end 67 | 68 | EventMachine.add_timer(1.5) { @channel.default_exchange.publish("Hi", :routing_key => "amqpgem.tests.a.queue") } 69 | end 70 | end 71 | end 72 | end -------------------------------------------------------------------------------- /spec/integration/regressions/empty_message_body_spec.rb: -------------------------------------------------------------------------------- 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 57 | -------------------------------------------------------------------------------- /spec/integration/regressions/issue66_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe "Immediate disconnection" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | include EventedSpec::SpecHelper 13 | 14 | 15 | after :all do 16 | done 17 | end 18 | 19 | it "succeeds" do 20 | c = AMQP.connect 21 | c.disconnect { 22 | done 23 | } 24 | end # it 25 | end # describe "Authentication attempt" 26 | -------------------------------------------------------------------------------- /spec/integration/remove_individual_binding_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | 5 | describe "An individual binding" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 3 14 | 15 | amqp_before do 16 | @channel = AMQP::Channel.new 17 | @channel.should be_open 18 | @channel.on_error do |ch, close| 19 | raise "Channel-level error!: #{close.inspect}" 20 | end 21 | end 22 | 23 | 24 | default_options AMQP_OPTS 25 | 26 | 27 | it "can be deleted by specifying routing key" do 28 | flag1 = false 29 | flag2 = false 30 | 31 | x = @channel.direct("amqpgem.examples.imaging") 32 | 33 | q = @channel.queue("", :exclusive => true) 34 | q.bind(x, :routing_key => "resize").bind(x, :routing_key => "watermark").subscribe do |meta, payload| 35 | flag1 = (meta.routing_key == "watermark") 36 | flag2 = (meta.routing_key == "resize") 37 | end 38 | 39 | EventMachine.add_timer(0.5) do 40 | q.unbind(x, :routing_key => "resize") do 41 | x.publish("some data", :routing_key => "resize") 42 | x.publish("some data", :routing_key => "watermark") 43 | end 44 | 45 | done(1.0) { 46 | flag1.should be_true 47 | flag2.should be_false 48 | } 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/integration/reply_queue_communication_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe "Exclusive server-named queue" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | 13 | default_timeout 2 14 | 15 | amqp_before do 16 | @channel = AMQP::Channel.new 17 | @channel.should be_open 18 | 19 | @exchange = AMQP::Exchange.default(@channel) 20 | end 21 | 22 | 23 | 24 | it "can be used for temporary point-to-point communication" do 25 | @exchange.channel.should == @channel 26 | 27 | @channel.queue("", :exclusive => true) do |queue1| 28 | puts "First callback has fired" 29 | @channel.queue("", :exclusive => true) do |queue2| 30 | puts "Second callback has fired" 31 | request_timestamp = Time.now.to_i 32 | reply_timestamp = nil 33 | 34 | queue1.subscribe do |header, body| 35 | header.timestamp.to_i.should == request_timestamp.to_i 36 | header.app_id.should == "Client" 37 | header.reply_to.should == queue2.name 38 | 39 | reply_timestamp = Time.now.to_i 40 | @exchange.publish(rand(1000), :routing_key => header.reply_to, :reply_to => queue1.name, :app_id => "Server", :timestamp => reply_timestamp) 41 | end 42 | 43 | queue2.subscribe do |header, body| 44 | header.timestamp.to_i.should == reply_timestamp.to_i 45 | header.app_id.should == "Server" 46 | header.reply_to.should == queue1.name 47 | end 48 | 49 | 50 | # publish the request 51 | @exchange.publish(rand(1000), 52 | :routing_key => queue1.name, 53 | :reply_to => queue2.name, 54 | :app_id => "Client", 55 | :timestamp => request_timestamp, 56 | :mandatory => true) 57 | 58 | done(0.2) { 59 | queue1.unsubscribe 60 | queue2.unsubscribe 61 | } 62 | end # do 63 | end # do 64 | end # it 65 | end # describe 66 | -------------------------------------------------------------------------------- /spec/integration/store_and_forward_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | describe "Store-and-forward routing" do 6 | 7 | # 8 | # Environment 9 | # 10 | 11 | include EventedSpec::AMQPSpec 12 | include EventedSpec::SpecHelper 13 | 14 | em_before { AMQP.cleanup_state } 15 | em_after { AMQP.cleanup_state } 16 | 17 | default_options AMQP_OPTS 18 | default_timeout 10 19 | 20 | amqp_before do 21 | @channel = AMQP::Channel.new 22 | @channel.should be_open 23 | end 24 | 25 | after(:all) do 26 | AMQP.cleanup_state 27 | done 28 | end 29 | 30 | 31 | # 32 | # Examples 33 | # 34 | 35 | context "that uses fanout exchange" do 36 | context "with a single bound queue" do 37 | amqp_before do 38 | @queue_name = "amqpgem.integration.snf.queue1" 39 | 40 | @exchange = @channel.direct("") 41 | @queue = @channel.queue(@queue_name, :auto_delete => true, :nowait => false) 42 | end 43 | 44 | it "allows asynchronous subscription to messages WITHOUT acknowledgements" do 45 | number_of_received_messages = 0 46 | # put a little pressure 47 | expected_number_of_messages = 300 48 | # It is always a good idea to use non-ASCII charachters in 49 | # various test suites. MK. 50 | dispatched_data = "messages sent at #{Time.now.to_i}" 51 | 52 | @queue.purge 53 | @queue.subscribe(:ack => false) do |payload| 54 | payload.should be_instance_of(String) 55 | number_of_received_messages += 1 56 | payload.should == dispatched_data 57 | end # subscribe 58 | 59 | delayed(0.3) do 60 | expected_number_of_messages.times do 61 | @exchange.publish(dispatched_data, :routing_key => @queue_name) 62 | end 63 | end 64 | 65 | done(4.0) { 66 | number_of_received_messages.should == expected_number_of_messages 67 | @queue.unsubscribe 68 | } 69 | end # it 70 | 71 | 72 | it "allows asynchronous subscription to messages WITH acknowledgements" do 73 | number_of_received_messages = 0 74 | expected_number_of_messages = 500 75 | 76 | @queue.subscribe(:ack => true) do |payload| 77 | number_of_received_messages += 1 78 | end # subscribe 79 | 80 | expected_number_of_messages.times do 81 | @exchange.publish(rand, :key => @queue_name) 82 | end 83 | 84 | # 5 seconds are for Rubinius, it is surprisingly slow on this workload 85 | done(5.0) { 86 | number_of_received_messages.should == expected_number_of_messages 87 | @queue.unsubscribe 88 | } 89 | end # it 90 | end 91 | end # context 92 | end # describe 93 | -------------------------------------------------------------------------------- /spec/integration/stress/publishing_of_messages_with_incrementing_sizes_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | 5 | # this example group ensures no message size is special 6 | # (with respect to framing edge cases). MK. 7 | describe "Stress test with messages with incrementing sizes" do 8 | 9 | # 10 | # Environment 11 | # 12 | 13 | include EventedSpec::AMQPSpec 14 | default_options AMQP_OPTS 15 | default_timeout 60 16 | 17 | amqp_before do 18 | @channel = AMQP::Channel.new 19 | @channel.on_error do |ch, close| 20 | raise "Channel-level error!: #{close.inspect}" 21 | end 22 | 23 | @queue = @channel.queue("", :auto_delete => true) 24 | @exchange = @channel.fanout("amqpgem.tests.integration.fanout.exchange", :auto_delete => true) 25 | 26 | @queue.bind(@exchange) 27 | end 28 | 29 | 30 | # 31 | # Examples 32 | # 33 | 34 | it "passes" do 35 | list = Range.new(0, 4785).to_a 36 | received = Array.new 37 | 38 | @queue.subscribe do |metadata, payload| 39 | received << payload.bytesize 40 | 41 | done if received == list 42 | end 43 | 44 | EventMachine.add_timer(1.0) do 45 | list.each do |n| 46 | @exchange.publish("i" * n) 47 | end 48 | end 49 | end 50 | end -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) 4 | 5 | require 'bundler' 6 | Bundler.setup(:default, :test) 7 | 8 | require "amqp" 9 | require "evented-spec" 10 | require "effin_utf8" 11 | require "multi_json" 12 | 13 | puts "Using Ruby #{RUBY_VERSION} and amq-protocol #{AMQ::Protocol::VERSION}" 14 | 15 | 16 | amqp_config = File.dirname(__FILE__) + '/amqp.yml' 17 | 18 | port = if ENV["TRACER"] 19 | 5673 20 | else 21 | 5672 22 | end 23 | 24 | if File.exists? amqp_config 25 | class Hash 26 | def symbolize_keys 27 | self.inject({}) do |result, (key, value)| 28 | new_key = key.is_a?(String) ? key.to_sym : key 29 | new_value = value.is_a?(Hash) ? value.symbolize_keys : value 30 | result[new_key] = new_value 31 | result 32 | end 33 | end 34 | end 35 | AMQP_OPTS = YAML::load_file(amqp_config).symbolize_keys[:test] 36 | else 37 | AMQP_OPTS = {:host => 'localhost', :port => port} 38 | end 39 | 40 | # puts "AMQP_OPTS = #{AMQP_OPTS.inspect}" 41 | 42 | # 43 | # Ruby version-specific 44 | # 45 | 46 | case RUBY_VERSION 47 | when "1.8.7" then 48 | class Array 49 | alias sample choice 50 | end 51 | when "1.8.6" then 52 | raise "Ruby 1.8.6 is not supported. Sorry, pal. Time to move on beyond One True Ruby. Yes, time flies by." 53 | end 54 | 55 | 56 | EventMachine.kqueue = true if EventMachine.kqueue? 57 | EventMachine.epoll = true if EventMachine.epoll? 58 | 59 | 60 | module RabbitMQ 61 | module Control 62 | def rabbitmq_pid 63 | $1.to_i if `rabbitmqctl status` =~ /\{pid,(\d+)\}/ 64 | end 65 | 66 | def start_rabbitmq(delay = 1.0) 67 | # this is Homebrew-specific :( 68 | `rabbitmq-server > /dev/null 2>&1 &`; sleep(delay) 69 | end 70 | 71 | def stop_rabbitmq(pid = rabbitmq_pid, delay = 1.0) 72 | `rabbitmqctl stop`; sleep(delay) 73 | end 74 | 75 | def kill_rabbitmq(pid = rabbitmq_pid, delay = 1.0) 76 | # tango is down, tango is down! 77 | Process.kill("KILL", pid); sleep(delay) 78 | end 79 | end 80 | end 81 | 82 | 83 | module PlatformDetection 84 | def mri? 85 | !defined?(RUBY_ENGINE) || (defined?(RUBY_ENGINE) && ("ruby" == RUBY_ENGINE)) 86 | end 87 | 88 | def rubinius? 89 | defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'rbx') 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /spec/unit/amqp/channel_id_allocation_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require "spec_helper" 4 | describe AMQP::ChannelIdAllocator do 5 | 6 | class ChannelAllocator 7 | include AMQP::ChannelIdAllocator 8 | end 9 | 10 | describe "#next_channel_id" do 11 | subject do 12 | ChannelAllocator.new 13 | end 14 | 15 | context "when there is a channel id available for allocation" do 16 | it "returns that channel id" do 17 | 1024.times { subject.next_channel_id } 18 | 19 | subject.next_channel_id.should == 1025 20 | end 21 | end 22 | 23 | context "when THERE IS NO a channel id available for allocation" do 24 | it "raises an exception" do 25 | (ChannelAllocator::MAX_CHANNELS_PER_CONNECTION - 1).times do 26 | subject.next_channel_id 27 | end 28 | 29 | lambda { subject.next_channel_id }.should raise_error 30 | end 31 | end 32 | end 33 | 34 | 35 | describe ".release_channel_id" do 36 | subject do 37 | ChannelAllocator.new 38 | end 39 | 40 | it "releases that channel id" do 41 | 1024.times { subject.next_channel_id } 42 | subject.next_channel_id.should == 1025 43 | 44 | subject.release_channel_id(128) 45 | subject.next_channel_id.should == 128 46 | subject.next_channel_id.should == 1026 47 | end 48 | end 49 | 50 | describe "each instance gets its own channel IDs" do 51 | it "has an allocator per instance" do 52 | one = ChannelAllocator.new 53 | two = ChannelAllocator.new 54 | one.next_channel_id.should == 1 55 | one.next_channel_id.should == 2 56 | two.next_channel_id.should == 1 57 | two.next_channel_id.should == 2 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/unit/amqp/connection_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | require 'amqp' 5 | 6 | describe AMQP do 7 | 8 | # 9 | # Examples 10 | # 11 | 12 | it "has default settings" do 13 | s = AMQP.settings.dup 14 | 15 | s[:host].should == "127.0.0.1" 16 | s[:port].should == 5672 17 | s[:user].should == "guest" 18 | s[:pass].should == "guest" 19 | s[:heartbeat].should be_nil 20 | s[:auth_mechanism].should eq([]) 21 | end 22 | 23 | describe "connection to RabbitMQ with a connection string" do 24 | include EventedSpec::SpecHelper 25 | 26 | em_before { AMQP.cleanup_state } 27 | em_after { AMQP.cleanup_state } 28 | 29 | it 'parses URI string' do 30 | em do 31 | AMQP.start("amqp://guest:guest@127.0.0.1?heartbeat=10&connection_timeout=100") do |session| 32 | expect(session.heartbeat_interval).to eq(10) 33 | expect(session.connection_timeout).to eq(100) 34 | session.close 35 | end 36 | done(0.3) 37 | end 38 | end 39 | end 40 | 41 | describe '.start' do 42 | 43 | # 44 | # Environment 45 | # 46 | 47 | include EventedSpec::SpecHelper 48 | 49 | em_before { AMQP.cleanup_state } 50 | em_after { AMQP.cleanup_state } 51 | 52 | # 53 | # Examples 54 | # 55 | 56 | it 'yields to given block AFTER connection is established' do 57 | em do 58 | AMQP.start AMQP_OPTS do 59 | @block_fired = true 60 | 61 | AMQP.connection.should be_connected 62 | end 63 | done(0.3) { @block_fired.should be_true } 64 | end 65 | end 66 | 67 | it 'should try to connect again in case previous conection failed' do 68 | em do 69 | timeout(20) 70 | error_handler = proc { EM.next_tick { AMQP.start(AMQP_OPTS) { done } } } 71 | # Assuming that you don't run your amqp @ port 65535 72 | AMQP.start(AMQP_OPTS.merge(:port => 65535, :on_tcp_connection_failure => error_handler)) 73 | 74 | end 75 | end 76 | 77 | it 'should keep connection if there was no failure' do 78 | em do 79 | error_handler = proc {} 80 | @block_fired_times = 0 81 | AMQP.start(AMQP_OPTS) { @block_fired_times += 1 } 82 | delayed(0.1) { AMQP.start(AMQP_OPTS) { @block_fired_times += 1 } } 83 | done(0.3) { @block_fired_times.should == 1 } 84 | end 85 | end 86 | end # .start 87 | end # describe AMQP 88 | --------------------------------------------------------------------------------