bunny 0.8.0 → 0.9.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -1
- data/.travis.yml +14 -4
- data/ChangeLog.md +72 -0
- data/Gemfile +17 -11
- data/README.md +82 -0
- data/bunny.gemspec +6 -13
- data/examples/connection/heartbeat.rb +17 -0
- data/lib/bunny.rb +40 -56
- data/lib/bunny/channel.rb +615 -19
- data/lib/bunny/channel_id_allocator.rb +59 -0
- data/lib/bunny/compatibility.rb +24 -0
- data/lib/bunny/concurrent/condition.rb +63 -0
- data/lib/bunny/consumer.rb +42 -26
- data/lib/bunny/consumer_tag_generator.rb +22 -0
- data/lib/bunny/consumer_work_pool.rb +67 -0
- data/lib/bunny/exceptions.rb +128 -0
- data/lib/bunny/exchange.rb +131 -136
- data/lib/bunny/framing.rb +53 -0
- data/lib/bunny/heartbeat_sender.rb +59 -0
- data/lib/bunny/main_loop.rb +70 -0
- data/lib/bunny/message_metadata.rb +126 -0
- data/lib/bunny/queue.rb +102 -275
- data/lib/bunny/session.rb +478 -0
- data/lib/bunny/socket.rb +44 -0
- data/lib/bunny/system_timer.rb +9 -9
- data/lib/bunny/transport.rb +179 -0
- data/lib/bunny/version.rb +1 -1
- data/spec/compatibility/queue_declare_spec.rb +40 -0
- data/spec/higher_level_api/integration/basic_ack_spec.rb +54 -0
- data/spec/higher_level_api/integration/basic_consume_spec.rb +51 -0
- data/spec/higher_level_api/integration/basic_get_spec.rb +47 -0
- data/spec/higher_level_api/integration/basic_nack_spec.rb +39 -0
- data/spec/higher_level_api/integration/basic_publish_spec.rb +105 -0
- data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -0
- data/spec/higher_level_api/integration/basic_recover_spec.rb +18 -0
- data/spec/higher_level_api/integration/basic_reject_spec.rb +53 -0
- data/spec/higher_level_api/integration/basic_return_spec.rb +33 -0
- data/spec/higher_level_api/integration/channel_close_spec.rb +29 -0
- data/spec/higher_level_api/integration/channel_flow_spec.rb +24 -0
- data/spec/higher_level_api/integration/channel_open_spec.rb +57 -0
- data/spec/higher_level_api/integration/channel_open_stress_spec.rb +22 -0
- data/spec/higher_level_api/integration/confirm_select_spec.rb +19 -0
- data/spec/higher_level_api/integration/connection_spec.rb +340 -0
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +31 -0
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +183 -0
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +37 -0
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +40 -0
- data/spec/higher_level_api/integration/queue_bind_spec.rb +109 -0
- data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -0
- data/spec/higher_level_api/integration/queue_delete_spec.rb +38 -0
- data/spec/higher_level_api/integration/queue_purge_spec.rb +30 -0
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +33 -0
- data/spec/higher_level_api/integration/tx_commit_spec.rb +21 -0
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +21 -0
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +57 -0
- data/spec/lower_level_api/integration/basic_consume_spec.rb +100 -0
- data/spec/spec_helper.rb +64 -0
- data/spec/unit/bunny_spec.rb +15 -0
- data/spec/unit/concurrent/condition_spec.rb +66 -0
- metadata +135 -93
- data/CHANGELOG +0 -21
- data/README.textile +0 -76
- data/Rakefile +0 -14
- data/examples/simple.rb +0 -32
- data/examples/simple_ack.rb +0 -35
- data/examples/simple_consumer.rb +0 -55
- data/examples/simple_fanout.rb +0 -41
- data/examples/simple_headers.rb +0 -42
- data/examples/simple_publisher.rb +0 -29
- data/examples/simple_topic.rb +0 -61
- data/ext/amqp-0.9.1.json +0 -389
- data/ext/config.yml +0 -4
- data/ext/qparser.rb +0 -426
- data/lib/bunny/client.rb +0 -370
- data/lib/bunny/subscription.rb +0 -92
- data/lib/qrack/amq-client-url.rb +0 -165
- data/lib/qrack/channel.rb +0 -20
- data/lib/qrack/client.rb +0 -247
- data/lib/qrack/errors.rb +0 -5
- data/lib/qrack/protocol/protocol.rb +0 -135
- data/lib/qrack/protocol/spec.rb +0 -525
- data/lib/qrack/qrack.rb +0 -20
- data/lib/qrack/queue.rb +0 -40
- data/lib/qrack/subscription.rb +0 -152
- data/lib/qrack/transport/buffer.rb +0 -305
- data/lib/qrack/transport/frame.rb +0 -102
- data/spec/spec_09/amqp_url_spec.rb +0 -19
- data/spec/spec_09/bunny_spec.rb +0 -76
- data/spec/spec_09/connection_spec.rb +0 -34
- data/spec/spec_09/exchange_spec.rb +0 -173
- data/spec/spec_09/queue_spec.rb +0 -240
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,11 +1,21 @@
|
|
1
1
|
bundler_args: --without development
|
2
|
-
|
2
|
+
before_script: "./bin/ci/before_build.sh"
|
3
|
+
script: "bundle exec rspec -c spec"
|
3
4
|
rvm:
|
4
5
|
- 1.8.7
|
5
|
-
- ree
|
6
6
|
- 1.9.2
|
7
7
|
- 1.9.3
|
8
|
+
- ruby-head
|
8
9
|
- rbx-18mode
|
9
|
-
|
10
|
+
- rbx-19mode
|
11
|
+
- jruby-19mode
|
10
12
|
notifications:
|
11
|
-
email:
|
13
|
+
email: michael@defprotocol.org
|
14
|
+
services:
|
15
|
+
- rabbitmq
|
16
|
+
branches:
|
17
|
+
only:
|
18
|
+
- master
|
19
|
+
- 0.8.x-stable
|
20
|
+
- 0.9.x-stable
|
21
|
+
- migrate_to_amq_protocol
|
data/ChangeLog.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Changes between Bunny 0.8.x and 0.9.0
|
2
|
+
|
3
|
+
## New convenience functions: Bunny::Channel#fanout, Bunny::Channel#topic
|
4
|
+
|
5
|
+
`Bunny::Channel#fanout`, `Bunny::Channel#topic`, `Bunny::Channel#direct`, `Bunny::Channel#headers`,
|
6
|
+
and`Bunny::Channel#default_exchange` are new convenience methods to instantiate exchanges:
|
7
|
+
|
8
|
+
``` ruby
|
9
|
+
conn = Bunny.new
|
10
|
+
conn.start
|
11
|
+
|
12
|
+
ch = conn.create_channel
|
13
|
+
x = ch.fanout("logging.events", :durable => true)
|
14
|
+
```
|
15
|
+
|
16
|
+
|
17
|
+
## Bunny::Queue#pop and consumer handlers (Bunny::Queue#subscribe) signatures have changed
|
18
|
+
|
19
|
+
Bunny `< 0.9.x` example:
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
h = queue.pop
|
23
|
+
|
24
|
+
puts h[:delivery_info], h[:header], h[:payload]
|
25
|
+
```
|
26
|
+
|
27
|
+
Bunny `>= 0.9.x` example:
|
28
|
+
|
29
|
+
``` ruby
|
30
|
+
delivery_info, properties, payload = queue.pop
|
31
|
+
```
|
32
|
+
|
33
|
+
The improve is both in that Ruby has positional destructuring, e.g.
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
delivery_info, _, content = q.pop
|
37
|
+
```
|
38
|
+
|
39
|
+
but not hash destructuring, like, say, Clojure does.
|
40
|
+
|
41
|
+
In addition we return nil for content when it should be nil
|
42
|
+
(basic.get-empty) and unify these arguments betwee
|
43
|
+
|
44
|
+
* Bunny::Queue#pop
|
45
|
+
|
46
|
+
* Consumer (Bunny::Queue#subscribe, etc) handlers
|
47
|
+
|
48
|
+
* Returned message handlers
|
49
|
+
|
50
|
+
The unification moment was the driving factor.
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
## Bunny::Client#write now raises Bunny::ConnectionError
|
55
|
+
|
56
|
+
Bunny::Client#write now raises `Bunny::ConnectionError` instead of `Bunny::ServerDownError` when network
|
57
|
+
I/O operations fail.
|
58
|
+
|
59
|
+
|
60
|
+
## Bunny::Client.create_channel now uses a bitset-based allocator
|
61
|
+
|
62
|
+
Instead of reusing channel instances, `Bunny::Client.create_channel` now opens new channels and
|
63
|
+
uses bitset-based allocator to keep track of used channel ids. This avoids situations when
|
64
|
+
channels are reused or shared without developer's explicit intent but also work well for
|
65
|
+
long running applications that aggressively open and release channels.
|
66
|
+
|
67
|
+
This is also how amqp gem and RabbitMQ Java client manage channel ids.
|
68
|
+
|
69
|
+
|
70
|
+
## Bunny::ServerDownError is now Bunny::TCPConnectionFailed
|
71
|
+
|
72
|
+
`Bunny::ServerDownError` is now an alias for `Bunny::TCPConnectionFailed`
|
data/Gemfile
CHANGED
@@ -21,19 +21,25 @@ extend Module.new {
|
|
21
21
|
|
22
22
|
gem "SystemTimer", "1.2", :platform => :ruby_18
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
gem "yard", ">= 0.7.2"
|
28
|
-
|
29
|
-
# Yard tags this buddy along.
|
30
|
-
gem "RedCloth", :platform => :mri
|
31
|
-
|
32
|
-
gem "changelog"
|
33
|
-
end
|
24
|
+
gem "rake"
|
25
|
+
gem "effin_utf8"
|
34
26
|
|
35
27
|
group :test do
|
36
|
-
gem "rspec", "~> 2.
|
28
|
+
gem "rspec", "~> 2.8.0"
|
37
29
|
end
|
38
30
|
|
39
31
|
gemspec
|
32
|
+
|
33
|
+
# Use local clones if possible.
|
34
|
+
# If you want to use your local copy, just symlink it to vendor.
|
35
|
+
def custom_gem(name, options = Hash.new)
|
36
|
+
local_path = File.expand_path("../vendor/#{name}", __FILE__)
|
37
|
+
if File.exist?(local_path)
|
38
|
+
puts "Using #{name} from #{local_path}..."
|
39
|
+
gem name, options.merge(:path => local_path).delete_if { |key, _| [:git, :branch].include?(key) }
|
40
|
+
else
|
41
|
+
gem name, options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
custom_gem "amq-protocol", :git => "git://github.com/ruby-amqp/amq-protocol.git", :branch => "master"
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# About Bunny
|
2
|
+
|
3
|
+
Bunny is a synchronous RabbitMQ client that focuses on ease of use.
|
4
|
+
|
5
|
+
|
6
|
+
## Supported Ruby Versions
|
7
|
+
|
8
|
+
It supports Ruby 1.9.3, 1.9.2, 1.8.7, Rubinius 2 and JRuby.
|
9
|
+
|
10
|
+
|
11
|
+
## Supported RabbitMQ Versions
|
12
|
+
|
13
|
+
Bunny versions `< 0.7.x` support RabbitMQ 1.x and 2.x. Bunny `0.8.x` and later versions only
|
14
|
+
supports RabbitMQ 2.x.
|
15
|
+
|
16
|
+
|
17
|
+
## Important: Bunny is about to undergo a lot of internal changes
|
18
|
+
|
19
|
+
Bunny is a very old library with **a lot** of missing functionality. It also implements an older version of the spec
|
20
|
+
and may or may not work with future RabbitMQ versions. As such, Bunny is about to undergo serious internal changes.
|
21
|
+
We will make our best to keep them as backwards compatible as possible but within reason.
|
22
|
+
|
23
|
+
See [this announcement](https://groups.google.com/forum/?fromgroups#!topic/ruby-amqp/crNVGEuHm68) to learn more.
|
24
|
+
|
25
|
+
In the meantime, consider using [Hot Bunnies](http://github.com/ruby-amqp/hot_bunnies) (JRuby-only) or [amqp gem](http://rubyamqp.info) instead.
|
26
|
+
|
27
|
+
|
28
|
+
## Quick Start for Bunny 0.7.x and 0.8.x
|
29
|
+
|
30
|
+
``` ruby
|
31
|
+
require "bunny"
|
32
|
+
|
33
|
+
b = Bunny.new(:logging => true)
|
34
|
+
|
35
|
+
# start a communication session with the amqp server
|
36
|
+
b.start
|
37
|
+
|
38
|
+
# declare a queue
|
39
|
+
q = b.queue("test1")
|
40
|
+
|
41
|
+
# declare default direct exchange which is bound to all queues
|
42
|
+
e = b.exchange("")
|
43
|
+
|
44
|
+
# publish a message to the exchange which then gets routed to the queue
|
45
|
+
e.publish("Hello, everybody!", :key => 'test1')
|
46
|
+
|
47
|
+
# get message from the queue
|
48
|
+
msg = q.pop[:payload]
|
49
|
+
|
50
|
+
puts "This is the message: " + msg + "\n\n"
|
51
|
+
|
52
|
+
# close the connection
|
53
|
+
b.stop
|
54
|
+
```
|
55
|
+
|
56
|
+
... or just:
|
57
|
+
|
58
|
+
```
|
59
|
+
require "bunny"
|
60
|
+
|
61
|
+
# Create a direct queue named "my_testq"
|
62
|
+
Bunny.run { |c| c.queue("my_testq") }
|
63
|
+
```
|
64
|
+
|
65
|
+
## Community & Getting Help
|
66
|
+
|
67
|
+
Please use [Ruby RabbitMQ clients Google Group](http://groups.google.com/group/ruby-amqp) for any questions you may
|
68
|
+
have.
|
69
|
+
|
70
|
+
For news and updates, [follow @rubyamqp](http://twitter.com/rubyamqp) on Twitter.
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
## Other Resources
|
75
|
+
|
76
|
+
* [AMQP 0.9.1 model explained](): introductory explanation of the AMQP v0.9.1 specification with particular reference to RabbitMQ.
|
77
|
+
|
78
|
+
|
79
|
+
## Links
|
80
|
+
|
81
|
+
* [Source code](http://github.com/ruby-amqp/bunny)
|
82
|
+
* [Blog](http://bunnyamqp.wordpress.com)
|
data/bunny.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.name = "bunny"
|
9
9
|
s.version = Bunny::VERSION.dup
|
10
10
|
s.homepage = "http://github.com/ruby-amqp/bunny"
|
11
|
-
s.summary = "
|
12
|
-
s.description = "
|
11
|
+
s.summary = "Easy to use synchronous Ruby client for RabbitMQ"
|
12
|
+
s.description = "Easy to use synchronous Ruby client for RabbitMQ"
|
13
13
|
|
14
14
|
# Sorted alphabetically.
|
15
15
|
s.authors = [
|
@@ -27,20 +27,13 @@ Gem::Specification.new do |s|
|
|
27
27
|
"c2thZXNAcmFpbHNleHByZXNzLmRl\n"].
|
28
28
|
map { |mail| Base64.decode64(mail) }
|
29
29
|
|
30
|
+
# Dependencies
|
31
|
+
s.add_dependency "amq-protocol", ">= 1.0.0"
|
32
|
+
|
30
33
|
# Files.
|
31
34
|
s.has_rdoc = true
|
32
|
-
s.extra_rdoc_files = ["README.
|
33
|
-
s.rdoc_options = ["--main", "README.rdoc"]
|
35
|
+
s.extra_rdoc_files = ["README.md"]
|
34
36
|
s.files = `git ls-files`.split("\n")
|
35
37
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
36
38
|
s.require_paths = ["lib"]
|
37
|
-
|
38
|
-
begin
|
39
|
-
require "changelog"
|
40
|
-
s.post_install_message = CHANGELOG.new.version_changes
|
41
|
-
rescue LoadError
|
42
|
-
end
|
43
|
-
|
44
|
-
# RubyForge
|
45
|
-
s.rubyforge_project = "bunny-amqp"
|
46
39
|
end
|
@@ -0,0 +1,17 @@
|
|
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 'bunny'
|
10
|
+
|
11
|
+
|
12
|
+
b = Bunny.new(:heartbeat_interval => 2)
|
13
|
+
b.start
|
14
|
+
|
15
|
+
c = b.create_channel
|
16
|
+
|
17
|
+
sleep 10
|
data/lib/bunny.rb
CHANGED
@@ -1,54 +1,67 @@
|
|
1
|
-
# encoding: utf-8
|
1
|
+
# -*- encoding: utf-8; mode: ruby -*-
|
2
2
|
|
3
|
-
require "socket"
|
4
|
-
require "thread"
|
5
3
|
require "timeout"
|
6
|
-
require "logger"
|
7
4
|
|
8
|
-
require
|
9
|
-
|
10
|
-
|
5
|
+
require "bunny/version"
|
6
|
+
require "amq/protocol/client"
|
7
|
+
|
8
|
+
require "bunny/framing"
|
9
|
+
require "bunny/exceptions"
|
10
|
+
require "bunny/socket"
|
11
|
+
|
12
|
+
# Core entities: connection, channel, exchange, queue, consumer
|
13
|
+
require "bunny/session"
|
14
|
+
require "bunny/channel"
|
15
|
+
require "bunny/exchange"
|
16
|
+
require "bunny/queue"
|
17
|
+
require "bunny/consumer"
|
11
18
|
|
12
19
|
module Bunny
|
20
|
+
PROTOCOL_VERSION = AMQ::Protocol::PROTOCOL_VERSION
|
21
|
+
|
22
|
+
# unifies Ruby standard library's Timeout (which is not accurate on
|
23
|
+
# Ruby 1.8 and has other issues) and SystemTimer (the gem)
|
24
|
+
Timer = if RUBY_VERSION < "1.9"
|
25
|
+
begin
|
26
|
+
require "bunny/system_timer"
|
27
|
+
Bunny::SystemTimer
|
28
|
+
rescue LoadError
|
29
|
+
Timeout
|
30
|
+
end
|
31
|
+
else
|
32
|
+
Timeout
|
33
|
+
end
|
13
34
|
|
14
|
-
class ConnectionError < StandardError; end
|
15
|
-
class ForcedChannelCloseError < StandardError; end
|
16
|
-
class ForcedConnectionCloseError < StandardError; end
|
17
|
-
class MessageError < StandardError; end
|
18
|
-
class ProtocolError < StandardError; end
|
19
|
-
class ServerDownError < StandardError; end
|
20
|
-
class UnsubscribeError < StandardError; end
|
21
|
-
class AcknowledgementError < StandardError; end
|
22
35
|
|
23
|
-
#
|
36
|
+
#
|
37
|
+
# API
|
38
|
+
#
|
24
39
|
|
25
40
|
def self.version
|
26
41
|
VERSION
|
27
42
|
end
|
28
43
|
|
29
|
-
|
30
|
-
|
31
|
-
warn "~ #{method} will be removed in Bunny #{version}. #{explanation}"
|
44
|
+
def self.protocol_version
|
45
|
+
AMQ::Protocol::PROTOCOL_VERSION
|
32
46
|
end
|
33
47
|
|
34
|
-
# Instantiates new Bunny::Client
|
35
48
|
|
36
|
-
def self.new(connection_string_or_opts =
|
37
|
-
# Set up Bunny
|
49
|
+
def self.new(connection_string_or_opts = {}, opts = {}, &block)
|
38
50
|
if connection_string_or_opts.respond_to?(:keys) && opts.empty?
|
39
51
|
opts = connection_string_or_opts
|
40
52
|
end
|
41
53
|
|
42
|
-
|
43
|
-
|
54
|
+
conn = Session.new(connection_string_or_opts, opts)
|
55
|
+
@default_connection ||= conn
|
56
|
+
|
57
|
+
conn
|
44
58
|
end
|
45
59
|
|
46
|
-
|
60
|
+
|
47
61
|
def self.run(connection_string_or_opts = {}, opts = {}, &block)
|
48
62
|
raise ArgumentError, 'Bunny#run requires a block' unless block
|
49
63
|
|
50
|
-
|
51
|
-
client = setup(connection_string_or_opts, opts)
|
64
|
+
client = Client.new(connection_string_or_opts, opts)
|
52
65
|
|
53
66
|
begin
|
54
67
|
client.start
|
@@ -57,35 +70,6 @@ module Bunny
|
|
57
70
|
client.stop
|
58
71
|
end
|
59
72
|
|
60
|
-
# Return success
|
61
73
|
:run_ok
|
62
74
|
end
|
63
|
-
|
64
|
-
Timer = if RUBY_VERSION < "1.9"
|
65
|
-
begin
|
66
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'system_timer.rb'))
|
67
|
-
Bunny::SystemTimer
|
68
|
-
rescue LoadError
|
69
|
-
Timeout
|
70
|
-
end
|
71
|
-
else
|
72
|
-
Timeout
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
|
77
|
-
def self.setup(*args)
|
78
|
-
# AMQP 0-9-1 specification
|
79
|
-
require 'qrack/qrack'
|
80
|
-
require 'bunny/client'
|
81
|
-
require 'bunny/exchange'
|
82
|
-
require 'bunny/queue'
|
83
|
-
require 'bunny/channel'
|
84
|
-
require 'bunny/subscription'
|
85
|
-
|
86
|
-
include Qrack
|
87
|
-
|
88
|
-
client = Bunny::Client.new(*args)
|
89
|
-
end
|
90
|
-
|
91
75
|
end
|
data/lib/bunny/channel.rb
CHANGED
@@ -1,39 +1,635 @@
|
|
1
|
-
|
1
|
+
require "thread"
|
2
|
+
require "amq/int_allocator"
|
3
|
+
|
4
|
+
require "bunny/consumer_work_pool"
|
5
|
+
|
6
|
+
require "bunny/exchange"
|
7
|
+
require "bunny/queue"
|
8
|
+
require "bunny/message_metadata"
|
2
9
|
|
3
10
|
module Bunny
|
4
|
-
class Channel
|
11
|
+
class Channel
|
12
|
+
|
13
|
+
#
|
14
|
+
# API
|
15
|
+
#
|
16
|
+
|
17
|
+
attr_accessor :id, :connection, :status, :work_pool
|
18
|
+
|
19
|
+
|
20
|
+
def initialize(connection = nil, id = nil, work_pool = ConsumerWorkPool.new(1))
|
21
|
+
@connection = connection
|
22
|
+
@id = id || @connection.next_channel_id
|
23
|
+
@status = :opening
|
24
|
+
|
25
|
+
@connection.register_channel(self)
|
5
26
|
|
6
|
-
|
7
|
-
|
27
|
+
@queues = Hash.new
|
28
|
+
@exchanges = Hash.new
|
29
|
+
@consumers = Hash.new
|
30
|
+
@work_pool = work_pool
|
31
|
+
|
32
|
+
# synchronizes frameset delivery. MK.
|
33
|
+
@mutex = Mutex.new
|
34
|
+
@consumer_mutex = Mutex.new
|
35
|
+
|
36
|
+
@continuations = ::Queue.new
|
8
37
|
end
|
9
38
|
|
39
|
+
|
10
40
|
def open
|
11
|
-
|
12
|
-
|
41
|
+
@connection.open_channel(self)
|
42
|
+
@status = :open
|
43
|
+
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def close
|
48
|
+
@connection.close_channel(self)
|
49
|
+
closed!
|
50
|
+
end
|
13
51
|
|
14
|
-
|
52
|
+
def open?
|
53
|
+
@status == :open
|
54
|
+
end
|
15
55
|
|
16
|
-
|
56
|
+
def closed?
|
57
|
+
@status == :closed
|
58
|
+
end
|
59
|
+
|
60
|
+
def queue(name = AMQ::Protocol::EMPTY_STRING, opts = {})
|
61
|
+
q = find_queue(name) || Bunny::Queue.new(self, name, opts)
|
17
62
|
|
18
|
-
|
19
|
-
:open_ok
|
63
|
+
register_queue(q)
|
20
64
|
end
|
21
65
|
|
22
|
-
def close
|
23
|
-
client.channel = self
|
24
|
-
client.send_frame(Qrack::Protocol::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0))
|
25
66
|
|
26
|
-
|
67
|
+
#
|
68
|
+
# Backwards compatibility with 0.8.0
|
69
|
+
#
|
27
70
|
|
28
|
-
|
71
|
+
def number
|
72
|
+
self.id
|
73
|
+
end
|
29
74
|
|
30
|
-
|
31
|
-
|
75
|
+
def active
|
76
|
+
@active
|
32
77
|
end
|
33
78
|
|
34
|
-
def
|
35
|
-
|
79
|
+
def client
|
80
|
+
@connection
|
81
|
+
end
|
82
|
+
|
83
|
+
def frame_size
|
84
|
+
@connection.frame_max
|
36
85
|
end
|
37
86
|
|
87
|
+
|
88
|
+
#
|
89
|
+
# Higher-level API, similar to amqp gem
|
90
|
+
#
|
91
|
+
|
92
|
+
def fanout(name, opts = {})
|
93
|
+
Exchange.new(self, :fanout, name, opts)
|
94
|
+
end
|
95
|
+
|
96
|
+
def direct(name, opts = {})
|
97
|
+
Exchange.new(self, :direct, name, opts)
|
98
|
+
end
|
99
|
+
|
100
|
+
def topic(name, opts = {})
|
101
|
+
Exchange.new(self, :topic, name, opts)
|
102
|
+
end
|
103
|
+
|
104
|
+
def headers(name, opts = {})
|
105
|
+
Exchange.new(self, :headers, name, opts)
|
106
|
+
end
|
107
|
+
|
108
|
+
def default_exchange
|
109
|
+
self.direct("", :no_declare => true)
|
110
|
+
end
|
111
|
+
|
112
|
+
def prefetch(prefetch_count)
|
113
|
+
self.basic_qos(prefetch_count, false)
|
114
|
+
end
|
115
|
+
|
116
|
+
def flow(active)
|
117
|
+
channel_flow(active)
|
118
|
+
end
|
119
|
+
|
120
|
+
def recover(ignored = true)
|
121
|
+
# RabbitMQ only supports basic.recover with requeue = true
|
122
|
+
basic_recover(true)
|
123
|
+
end
|
124
|
+
|
125
|
+
def reject(delivery_tag, requeue = false)
|
126
|
+
basic_reject(delivery_tag, requeue)
|
127
|
+
end
|
128
|
+
|
129
|
+
def ack(delivery_tag, multiple)
|
130
|
+
basic_ack(delivery_tag, multiple)
|
131
|
+
end
|
132
|
+
alias acknowledge ack
|
133
|
+
|
134
|
+
def nack(delivery_tag, requeue, multiple = false)
|
135
|
+
basic_nack(delivery_tag, requeue, multiple)
|
136
|
+
end
|
137
|
+
|
138
|
+
def on_error(&block)
|
139
|
+
@default_error_handler = block
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
#
|
144
|
+
# Lower-level API, exposes protocol operations as they are defined in the protocol,
|
145
|
+
# without any OO sugar on top, by design.
|
146
|
+
#
|
147
|
+
|
148
|
+
# basic.*
|
149
|
+
|
150
|
+
def basic_publish(payload, exchange, routing_key, opts = {})
|
151
|
+
raise_if_no_longer_open!
|
152
|
+
|
153
|
+
exchange_name = if exchange.respond_to?(:name)
|
154
|
+
exchange.name
|
155
|
+
else
|
156
|
+
exchange
|
157
|
+
end
|
158
|
+
|
159
|
+
meta = { :priority => 0, :delivery_mode => 2, :content_type => "application/octet-stream" }.
|
160
|
+
merge(opts)
|
161
|
+
@connection.send_frameset(AMQ::Protocol::Basic::Publish.encode(@id, payload, meta, exchange_name, routing_key, meta[:mandatory], false, (frame_size || @connection.frame_max)), self)
|
162
|
+
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def basic_get(queue, opts = {:ack => true})
|
167
|
+
raise_if_no_longer_open!
|
168
|
+
|
169
|
+
@connection.send_frame(AMQ::Protocol::Basic::Get.encode(@id, queue, !opts[:ack]))
|
170
|
+
@last_basic_get_response = @continuations.pop
|
171
|
+
|
172
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
173
|
+
@last_basic_get_response
|
174
|
+
end
|
175
|
+
|
176
|
+
def basic_qos(prefetch_count, global = false)
|
177
|
+
raise ArgumentError.new("prefetch count must be a positive integer, given: #{prefetch_count}") if prefetch_count < 0
|
178
|
+
raise_if_no_longer_open!
|
179
|
+
|
180
|
+
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0, prefetch_count, global))
|
181
|
+
|
182
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
183
|
+
@last_basic_qos_ok = @continuations.pop
|
184
|
+
end
|
185
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
186
|
+
|
187
|
+
@last_basic_qos_ok
|
188
|
+
end
|
189
|
+
|
190
|
+
def basic_recover(requeue)
|
191
|
+
raise_if_no_longer_open!
|
192
|
+
|
193
|
+
@connection.send_frame(AMQ::Protocol::Basic::Recover.encode(@id, requeue))
|
194
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
195
|
+
@last_basic_recover_ok = @continuations.pop
|
196
|
+
end
|
197
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
198
|
+
|
199
|
+
@last_basic_recover_ok
|
200
|
+
end
|
201
|
+
|
202
|
+
def basic_reject(delivery_tag, requeue)
|
203
|
+
raise_if_no_longer_open!
|
204
|
+
@connection.send_frame(AMQ::Protocol::Basic::Reject.encode(@id, delivery_tag, requeue))
|
205
|
+
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
|
209
|
+
def basic_ack(delivery_tag, multiple)
|
210
|
+
raise_if_no_longer_open!
|
211
|
+
@connection.send_frame(AMQ::Protocol::Basic::Ack.encode(@id, delivery_tag, multiple))
|
212
|
+
|
213
|
+
nil
|
214
|
+
end
|
215
|
+
|
216
|
+
def basic_nack(delivery_tag, requeue, multiple = false)
|
217
|
+
raise_if_no_longer_open!
|
218
|
+
@connection.send_frame(AMQ::Protocol::Basic::Nack.encode(@id, delivery_tag, requeue, multiple))
|
219
|
+
|
220
|
+
nil
|
221
|
+
end
|
222
|
+
|
223
|
+
def basic_consume(queue, consumer_tag = generate_consumer_tag, no_ack = false, exclusive = false, arguments = nil, &block)
|
224
|
+
raise_if_no_longer_open!
|
225
|
+
maybe_start_consumer_work_pool!
|
226
|
+
|
227
|
+
queue_name = if queue.respond_to?(:name)
|
228
|
+
queue.name
|
229
|
+
else
|
230
|
+
queue
|
231
|
+
end
|
232
|
+
|
233
|
+
@connection.send_frame(AMQ::Protocol::Basic::Consume.encode(@id, queue_name, consumer_tag, false, no_ack, exclusive, false, arguments))
|
234
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
235
|
+
@last_basic_consume_ok = @continuations.pop
|
236
|
+
end
|
237
|
+
|
238
|
+
@consumer_mutex.synchronize do
|
239
|
+
c = Consumer.new(self, queue, consumer_tag, no_ack, exclusive, arguments)
|
240
|
+
c.on_delivery(&block) if block
|
241
|
+
|
242
|
+
@consumers[@last_basic_consume_ok.consumer_tag] = c
|
243
|
+
end
|
244
|
+
|
245
|
+
@last_basic_consume_ok
|
246
|
+
end
|
247
|
+
|
248
|
+
def basic_cancel(consumer_tag)
|
249
|
+
@connection.send_frame(AMQ::Protocol::Basic::Cancel.encode(@id, consumer_tag, false))
|
250
|
+
|
251
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
252
|
+
@last_basic_cancel_ok = @continuations.pop
|
253
|
+
end
|
254
|
+
|
255
|
+
@last_basic_cancel_ok
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
# queue.*
|
260
|
+
|
261
|
+
def queue_declare(name, opts = {})
|
262
|
+
raise_if_no_longer_open!
|
263
|
+
|
264
|
+
@connection.send_frame(AMQ::Protocol::Queue::Declare.encode(@id, name, opts.fetch(:passive, false), opts.fetch(:durable, false), opts.fetch(:exclusive, false), opts.fetch(:auto_delete, false), false, opts[:arguments]))
|
265
|
+
@last_queue_declare_ok = @continuations.pop
|
266
|
+
|
267
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
268
|
+
|
269
|
+
@last_queue_declare_ok
|
270
|
+
end
|
271
|
+
|
272
|
+
def queue_delete(name, opts = {})
|
273
|
+
raise_if_no_longer_open!
|
274
|
+
|
275
|
+
@connection.send_frame(AMQ::Protocol::Queue::Delete.encode(@id, name, opts[:if_unused], opts[:if_empty], false))
|
276
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
277
|
+
@last_queue_delete_ok = @continuations.pop
|
278
|
+
end
|
279
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
280
|
+
|
281
|
+
@last_queue_delete_ok
|
282
|
+
end
|
283
|
+
|
284
|
+
def queue_purge(name, opts = {})
|
285
|
+
raise_if_no_longer_open!
|
286
|
+
|
287
|
+
@connection.send_frame(AMQ::Protocol::Queue::Purge.encode(@id, name, false))
|
288
|
+
|
289
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
290
|
+
@last_queue_purge_ok = @continuations.pop
|
291
|
+
end
|
292
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
293
|
+
|
294
|
+
@last_queue_purge_ok
|
295
|
+
end
|
296
|
+
|
297
|
+
def queue_bind(name, exchange, opts = {})
|
298
|
+
raise_if_no_longer_open!
|
299
|
+
|
300
|
+
exchange_name = if exchange.respond_to?(:name)
|
301
|
+
exchange.name
|
302
|
+
else
|
303
|
+
exchange
|
304
|
+
end
|
305
|
+
|
306
|
+
@connection.send_frame(AMQ::Protocol::Queue::Bind.encode(@id, name, exchange_name, opts[:routing_key], false, opts[:arguments]))
|
307
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
308
|
+
@last_queue_bind_ok = @continuations.pop
|
309
|
+
end
|
310
|
+
|
311
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
312
|
+
@last_queue_bind_ok
|
313
|
+
end
|
314
|
+
|
315
|
+
def queue_unbind(name, exchange, opts = {})
|
316
|
+
raise_if_no_longer_open!
|
317
|
+
|
318
|
+
exchange_name = if exchange.respond_to?(:name)
|
319
|
+
exchange.name
|
320
|
+
else
|
321
|
+
exchange
|
322
|
+
end
|
323
|
+
|
324
|
+
@connection.send_frame(AMQ::Protocol::Queue::Unbind.encode(@id, name, exchange_name, opts[:routing_key], opts[:arguments]))
|
325
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
326
|
+
@last_queue_unbind_ok = @continuations.pop
|
327
|
+
end
|
328
|
+
|
329
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
330
|
+
@last_queue_unbind_ok
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
# exchange.*
|
335
|
+
|
336
|
+
def exchange_declare(name, type, opts = {})
|
337
|
+
raise_if_no_longer_open!
|
338
|
+
|
339
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@id, name, type.to_s, opts.fetch(:passive, false), opts.fetch(:durable, false), opts.fetch(:auto_delete, false), false, false, opts[:arguments]))
|
340
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
341
|
+
@last_exchange_declare_ok = @continuations.pop
|
342
|
+
end
|
343
|
+
|
344
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
345
|
+
@last_exchange_declare_ok
|
346
|
+
end
|
347
|
+
|
348
|
+
def exchange_delete(name, opts = {})
|
349
|
+
raise_if_no_longer_open!
|
350
|
+
|
351
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Delete.encode(@id, name, opts[:if_unused], false))
|
352
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
353
|
+
@last_exchange_delete_ok = @continuations.pop
|
354
|
+
end
|
355
|
+
|
356
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
357
|
+
@last_exchange_delete_ok
|
358
|
+
end
|
359
|
+
|
360
|
+
def exchange_bind(source, destination, opts = {})
|
361
|
+
raise_if_no_longer_open!
|
362
|
+
|
363
|
+
source_name = if source.respond_to?(:name)
|
364
|
+
source.name
|
365
|
+
else
|
366
|
+
source
|
367
|
+
end
|
368
|
+
|
369
|
+
destination_name = if destination.respond_to?(:name)
|
370
|
+
destination.name
|
371
|
+
else
|
372
|
+
destination
|
373
|
+
end
|
374
|
+
|
375
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Bind.encode(@id, destination_name, source_name, opts[:routing_key], false, opts[:arguments]))
|
376
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
377
|
+
@last_exchange_bind_ok = @continuations.pop
|
378
|
+
end
|
379
|
+
|
380
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
381
|
+
@last_exchange_bind_ok
|
382
|
+
end
|
383
|
+
|
384
|
+
def exchange_unbind(source, destination, opts = {})
|
385
|
+
raise_if_no_longer_open!
|
386
|
+
|
387
|
+
source_name = if source.respond_to?(:name)
|
388
|
+
source.name
|
389
|
+
else
|
390
|
+
source
|
391
|
+
end
|
392
|
+
|
393
|
+
destination_name = if destination.respond_to?(:name)
|
394
|
+
destination.name
|
395
|
+
else
|
396
|
+
destination
|
397
|
+
end
|
398
|
+
|
399
|
+
@connection.send_frame(AMQ::Protocol::Exchange::Unbind.encode(@id, destination_name, source_name, opts[:routing_key], false, opts[:arguments]))
|
400
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
401
|
+
@last_exchange_unbind_ok = @continuations.pop
|
402
|
+
end
|
403
|
+
|
404
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
405
|
+
@last_exchange_unbind_ok
|
406
|
+
end
|
407
|
+
|
408
|
+
# channel.*
|
409
|
+
|
410
|
+
def channel_flow(active)
|
411
|
+
raise_if_no_longer_open!
|
412
|
+
|
413
|
+
@connection.send_frame(AMQ::Protocol::Channel::Flow.encode(@id, active))
|
414
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
415
|
+
@last_channel_flow_ok = @continuations.pop
|
416
|
+
end
|
417
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
418
|
+
|
419
|
+
@last_channel_flow_ok
|
420
|
+
end
|
421
|
+
|
422
|
+
# tx.*
|
423
|
+
|
424
|
+
def tx_select
|
425
|
+
raise_if_no_longer_open!
|
426
|
+
|
427
|
+
@connection.send_frame(AMQ::Protocol::Tx::Select.encode(@id))
|
428
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
429
|
+
@last_tx_select_ok = @continuations.pop
|
430
|
+
end
|
431
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
432
|
+
|
433
|
+
@last_tx_select_ok
|
434
|
+
end
|
435
|
+
|
436
|
+
def tx_commit
|
437
|
+
raise_if_no_longer_open!
|
438
|
+
|
439
|
+
@connection.send_frame(AMQ::Protocol::Tx::Commit.encode(@id))
|
440
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
441
|
+
@last_tx_commit_ok = @continuations.pop
|
442
|
+
end
|
443
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
444
|
+
|
445
|
+
@last_tx_commit_ok
|
446
|
+
end
|
447
|
+
|
448
|
+
def tx_rollback
|
449
|
+
raise_if_no_longer_open!
|
450
|
+
|
451
|
+
@connection.send_frame(AMQ::Protocol::Tx::Rollback.encode(@id))
|
452
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
453
|
+
@last_tx_rollback_ok = @continuations.pop
|
454
|
+
end
|
455
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
456
|
+
|
457
|
+
@last_tx_rollback_ok
|
458
|
+
end
|
459
|
+
|
460
|
+
# confirm.*
|
461
|
+
|
462
|
+
def confirm_select
|
463
|
+
raise_if_no_longer_open!
|
464
|
+
|
465
|
+
@connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id, false))
|
466
|
+
Bunny::Timer.timeout(1, ClientTimeout) do
|
467
|
+
@last_confirm_select_ok = @continuations.pop
|
468
|
+
end
|
469
|
+
raise_if_continuation_resulted_in_a_channel_error!
|
470
|
+
|
471
|
+
@last_confirm_select_ok
|
472
|
+
end
|
473
|
+
|
474
|
+
|
475
|
+
#
|
476
|
+
# Implementation
|
477
|
+
#
|
478
|
+
|
479
|
+
def handle_method(method)
|
480
|
+
# puts "Channel#handle_frame on channel #{@id}: #{method.inspect}"
|
481
|
+
case method
|
482
|
+
when AMQ::Protocol::Queue::DeclareOk then
|
483
|
+
@continuations.push(method)
|
484
|
+
when AMQ::Protocol::Queue::DeleteOk then
|
485
|
+
@continuations.push(method)
|
486
|
+
when AMQ::Protocol::Queue::PurgeOk then
|
487
|
+
@continuations.push(method)
|
488
|
+
when AMQ::Protocol::Queue::BindOk then
|
489
|
+
@continuations.push(method)
|
490
|
+
when AMQ::Protocol::Queue::UnbindOk then
|
491
|
+
@continuations.push(method)
|
492
|
+
when AMQ::Protocol::Exchange::BindOk then
|
493
|
+
@continuations.push(method)
|
494
|
+
when AMQ::Protocol::Exchange::UnbindOk then
|
495
|
+
@continuations.push(method)
|
496
|
+
when AMQ::Protocol::Exchange::DeclareOk then
|
497
|
+
@continuations.push(method)
|
498
|
+
when AMQ::Protocol::Exchange::DeleteOk then
|
499
|
+
@continuations.push(method)
|
500
|
+
when AMQ::Protocol::Basic::QosOk then
|
501
|
+
@continuations.push(method)
|
502
|
+
when AMQ::Protocol::Basic::RecoverOk then
|
503
|
+
@continuations.push(method)
|
504
|
+
when AMQ::Protocol::Channel::FlowOk then
|
505
|
+
@continuations.push(method)
|
506
|
+
when AMQ::Protocol::Basic::ConsumeOk then
|
507
|
+
@continuations.push(method)
|
508
|
+
when AMQ::Protocol::Basic::CancelOk then
|
509
|
+
@continuations.push(method)
|
510
|
+
@consumers.delete(method.consumer_tag)
|
511
|
+
when AMQ::Protocol::Tx::SelectOk, AMQ::Protocol::Tx::CommitOk, AMQ::Protocol::Tx::RollbackOk then
|
512
|
+
@continuations.push(method)
|
513
|
+
when AMQ::Protocol::Tx::SelectOk then
|
514
|
+
@continuations.push(method)
|
515
|
+
when AMQ::Protocol::Confirm::SelectOk then
|
516
|
+
@continuations.push(method)
|
517
|
+
when AMQ::Protocol::Channel::Close then
|
518
|
+
# puts "Exception on channel #{@id}: #{method.reply_code} #{method.reply_text}"
|
519
|
+
closed!
|
520
|
+
@connection.send_frame(AMQ::Protocol::Channel::CloseOk.encode(@id))
|
521
|
+
|
522
|
+
@last_channel_error = instantiate_channel_level_exception(method)
|
523
|
+
@continuations.push(method)
|
524
|
+
when AMQ::Protocol::Channel::CloseOk then
|
525
|
+
@continuations.push(method)
|
526
|
+
else
|
527
|
+
raise "Do not know how to handle #{method.inspect} in Bunny::Channel#handle_method"
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
def handle_basic_get_ok(basic_get_ok, properties, content)
|
532
|
+
@continuations.push([basic_get_ok, properties, content])
|
533
|
+
end
|
534
|
+
|
535
|
+
def handle_basic_get_empty(basic_get_empty)
|
536
|
+
@continuations.push([nil, nil, nil])
|
537
|
+
end
|
538
|
+
|
539
|
+
def handle_frameset(basic_deliver, properties, content)
|
540
|
+
consumer = @consumers[basic_deliver.consumer_tag]
|
541
|
+
if consumer
|
542
|
+
@work_pool.submit do
|
543
|
+
consumer.call(MessageMetadata.new(basic_deliver, properties), content)
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
def handle_basic_return(basic_return, properties, content)
|
549
|
+
x = find_exchange(basic_return.exchange)
|
550
|
+
|
551
|
+
if x
|
552
|
+
x.handle_return(basic_return, properties, content)
|
553
|
+
else
|
554
|
+
# TODO: log a warning
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
# Starts consumer work pool. Lazily called by #basic_consume to avoid creating new threads
|
559
|
+
# that won't do any real work for channels that do not register consumers (e.g. only used for
|
560
|
+
# publishing). MK.
|
561
|
+
def maybe_start_consumer_work_pool!
|
562
|
+
@work_pool.start unless @work_pool.started?
|
563
|
+
end
|
564
|
+
|
565
|
+
def read_next_frame(options = {})
|
566
|
+
@connection.read_next_frame(options = {})
|
567
|
+
end
|
568
|
+
|
569
|
+
# Synchronizes given block using this channel's mutex.
|
570
|
+
# @api public
|
571
|
+
def synchronize(&block)
|
572
|
+
@mutex.synchronize(&block)
|
573
|
+
end
|
574
|
+
|
575
|
+
def register_queue(queue)
|
576
|
+
@queues[queue.name] = queue
|
577
|
+
end
|
578
|
+
|
579
|
+
def find_queue(name)
|
580
|
+
@queues[name]
|
581
|
+
end
|
582
|
+
|
583
|
+
def register_exchange(exchange)
|
584
|
+
@exchanges[exchange.name] = exchange
|
585
|
+
end
|
586
|
+
|
587
|
+
def find_exchange(name)
|
588
|
+
@exchanges[name]
|
589
|
+
end
|
590
|
+
|
591
|
+
protected
|
592
|
+
|
593
|
+
def closed!
|
594
|
+
@status = :closed
|
595
|
+
@work_pool.shutdown
|
596
|
+
@connection.release_channel_id(@id)
|
597
|
+
end
|
598
|
+
|
599
|
+
def instantiate_channel_level_exception(frame)
|
600
|
+
case frame
|
601
|
+
when AMQ::Protocol::Channel::Close then
|
602
|
+
klass = case frame.reply_code
|
603
|
+
when 403 then
|
604
|
+
AccessRefused
|
605
|
+
when 404 then
|
606
|
+
NotFound
|
607
|
+
when 405 then
|
608
|
+
ResourceLocked
|
609
|
+
when 406 then
|
610
|
+
PreconditionFailed
|
611
|
+
else
|
612
|
+
ChannelLevelException
|
613
|
+
end
|
614
|
+
|
615
|
+
klass.new(frame.reply_text, self, frame)
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
def raise_if_continuation_resulted_in_a_channel_error!
|
620
|
+
raise @last_channel_error if @last_channel_error
|
621
|
+
end
|
622
|
+
|
623
|
+
def raise_if_no_longer_open!
|
624
|
+
raise ChannelAlreadyClosed.new("cannot use a channel that was already closed! Channel id: #{@id}", self) if closed?
|
625
|
+
end
|
626
|
+
|
627
|
+
# Unique string supposed to be used as a consumer tag.
|
628
|
+
#
|
629
|
+
# @return [String] Unique string.
|
630
|
+
# @api plugin
|
631
|
+
def generate_consumer_tag(name = "bunny")
|
632
|
+
"#{name}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}"
|
633
|
+
end
|
38
634
|
end
|
39
635
|
end
|