bunny 0.8.0 → 0.9.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|