Overview

What are AMQP channels

AMQP is a multi-channelled protocol. Channels provide a way to multiplex
a heavyweight TCP/IP connection into several light weight connections.
This makes the protocol more “firewall friendly” since port usage is predictable.
It also means that traffic shaping and other network QoS features can be easily employed.
Channels are independent of each other and can perform different functions simultaneously
with other channels, the available bandwidth being shared between the concurrent activities.

Opening a channel

Channels are opened asynchronously. There are two ways to do it: using a callback or pseudo-synchronous mode.

Unless your application needs multiple channels, this approach is recommended. Alternatively,
AMQP::Channel can be instantiated without a block. Then returned channel is not immediately open,
however, it can be used as if it was a synchronous, blocking method:

Even though in the example above channel isn’t immediately open, it is safe to declare exchanges using
it. Exchange declaration will be delayed until after channel is open. Same applies to queue declaration
and other operations on exchanges and queues. Library methods that rely on channel being open will be
enqueued and executed in a FIFO manner when broker confirms channel opening.
Note, however, that this “pseudo-synchronous mode” is easy to abuse and introduce race conditions AMQP gem
cannot resolve for you. AMQP is an inherently asynchronous protocol and AMQP gem embraces this fact.

Error handling

It is possible (and, indeed, recommended) to handle channel-level exceptions by defining an errback using #on_error:

When channel-level exception is indicated by the broker and errback defined using #on_error is run, channel is already
closed and all queue and exchange objects associated with this channel are reset. The recommended way to recover from
channel-level exceptions is to open a new channel and re-instantiate queues, exchanges and bindings your application
needs.

Closing a channel

Channels are opened when objects is instantiated and closed using #close method when application no longer
needs it.

RabbitMQ extensions.

# this assumes EventMachine reactor is running
AMQP.connect("amqp://guest:guest@dev.rabbitmq.com:5672")do|client|AMQP::Channel.new(client)do|channel,open_ok|# when this block is executed, channel is open and ready for use
endend

Instantiating a channel that will be open eventually

# this assumes EventMachine reactor is running
AMQP.connect("amqp://guest:guest@dev.rabbitmq.com:5672")do|client|channel=AMQP::Channel.new(client)exchange=channel.default_exchange# ...
end

Queue declaration with incompatible attributes results in a channel-level exception

AMQP.start("amqp://guest:guest@dev.rabbitmq.com:5672")do|connection,open_ok|AMQP::Channel.newdo|channel,open_ok|puts"Channel ##{channel.id} is now open!"channel.on_errordo|ch,close|puts"Handling channel-level exception"connection.close{EM.stop{exit}}endEventMachine.add_timer(0.4)do# these two definitions result in a race condition. For sake of this example,
# however, it does not matter. Whatever definition succeeds first, 2nd one will
# cause a channel-level exception (because attributes are not identical)
AMQP::Queue.new(channel,"amqpgem.examples.channel_exception",:auto_delete=>true,:durable=>false)do|queue|puts"#{queue.name} is ready to go"endAMQP::Queue.new(channel,"amqpgem.examples.channel_exception",:auto_delete=>true,:durable=>true)do|queue|puts"#{queue.name} is ready to go"endendendend

Closing a channel your application no longer needs

# this assumes EventMachine reactor is running
AMQP.connect("amqp://guest:guest@dev.rabbitmq.com:5672")do|client|AMQP::Channel.new(client)do|channel,open_ok|channel.closedo|close_ok|# when this block is executed, channel is successfully closed
endendend

# File 'lib/amqp/channel.rb', line 233definitialize(connection=nil,id=nil,options={},&block)raise'AMQP can only be used from within EM.run {}'unlessEM.reactor_running?@connection=connection||AMQP.connection||AMQP.start# this means 2nd argument is options
ifid.kind_of?(Hash)options=options.merge(id)id=@connection.next_channel_idendsuper(@connection)@id=id||@connection.next_channel_id@exchanges=Hash.new@queues=Hash.new@consumers=Hash.new@options={:auto_recovery=>@connection.auto_recovering?}.merge(options)@auto_recovery=(!!@options[:auto_recovery])# we must synchronize frameset delivery. MK.
@mutex=Mutex.newreset_state!# 65536 is here for cases when channel is opened without passing a callback in,
# otherwise channel_mix would be nil and it causes a lot of needless headaches.
# lets just have this default. MK.
channel_max=if@connection.open?@connection.channel_max||65536else65536endifchannel_max!=0&&!(0..channel_max).include?(@id)raiseArgumentError.new("Max channel for the connection is #{channel_max}, given: #{@id}")end# we need this deferrable to mimic what AMQP gem 0.7 does to enable
# the following (pseudo-synchronous) style of programming some people use in their
# existing codebases:
#
# connection = AMQP.connect
# channel = AMQP::Channel.new(connection)
# queue = AMQP::Queue.new(channel)
#
# ...
#
# Read more about EM::Deferrable#callback behavior in EventMachine documentation. MK.
@channel_is_open_deferrable=AMQP::Deferrable.new@parameter_checks={:queue=>[:durable,:exclusive,:auto_delete,:arguments],:exchange=>[:type,:durable,:arguments]}# only send channel.open when connection is actually open. Makes it possible to
# do c = AMQP.connect; AMQP::Channel.new(c) that is what some people do. MK.
@connection.on_connectiondoself.opendo|ch,open_ok|@channel_is_open_deferrable.succeedifblockcaseblock.aritywhen1thenblock.call(ch)elseblock.call(ch,open_ok)end# case
end# if
self.prefetch(@options[:prefetch],false)if@options[:prefetch]end# self.open
end# @connection.on_open
end

#flow_is_active ⇒ Object

#id ⇒ Object(readonly)

Returns the value of attribute id

173
174
175

# File 'lib/amqp/channel.rb', line 173defid@idend

#publisher_index ⇒ Integer

Publisher index is an index of the last message since
the confirmations were activated, started with 0. It’s
incremented by 1 every time a message is published.
This is done on both client and server, hence this
acknowledged messages can be matched via its delivery-tag.

#before_recovery(&block) ⇒ Object

Defines a callback that will be executed after TCP connection has recovered after a network failure
but before AMQP connection is re-opened.
Only one callback can be defined (the one defined last replaces previously added ones).

#confirm_select(nowait = false, &block) ⇒ Object

# File 'lib/amqp/channel.rb', line 1119defconfirm_select(nowait=false,&block)self.once_opendoifnowait&&blockraiseArgumentError,"confirm.select with nowait = true and a callback makes no sense"end@uses_publisher_confirmations=truereset_publisher_index!self.redefine_callback(:confirm_select,&block)unlessnowaitself.redefine_callback(:after_publish)doincrement_publisher_index!end@connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id,nowait))selfendend

Returns exchange object with the same name as default (aka unnamed) exchange.
Default exchange is a direct exchange and automatically routes messages to
queues when routing key matches queue name exactly. This feature is known as
“automatic binding” (of queues to default exchange).

Use default exchange when you want to route messages directly to specific queues
(queue names are known, you don’t mind this kind of coupling between applications).

Using default pre-declared direct exchange and no callbacks (pseudo-synchronous style)

# an exchange application A will be using to publish updates
# to some search index
exchange=channel.direct("index.updates")# In the same (or different) process declare a queue that broker will
# generate name for, bind it to aforementioned exchange using method chaining
queue=channel.queue("").# queue will be receiving messages that were published with
# :routing_key attribute value of "search.index.updates"
bind(exchange,:routing_key=>"search.index.updates").# register a callback that will be run when messages arrive
subscribe{|header,message|puts("Received #{message}")}# now publish a new document contents for indexing,
# message will be delivered to the queue we declared and bound on the line above
exchange.publish(document.content,:routing_key=>"search.index.updates")

AMQP.connectdo|connection|AMQP::Channel.new(connection)do|channel|channel.direct("email.replies_listener")do|exchange,declare_ok|# by now exchange is ready and waiting
endendend

Parameters:

name(String)(defaults to: 'amq.direct')
—

(amq.direct) Exchange name.

opts(Hash)(defaults to: {})
—

a customizable set of options

Options Hash (opts):

:passive(Boolean)
— default:
false
—

If set, the server will not create the exchange if it does not
already exist. The client can use this to check whether an exchange
exists without modifying the server state.

:durable(Boolean)
— default:
false
—

If set when creating a new exchange, the exchange will be marked as
durable. Durable exchanges and their bindings are recreated upon a server
restart (information about them is persisted). Non-durable (transient) exchanges
do not survive if/when a server restarts (information about them is stored exclusively
in RAM).

:auto_delete(Boolean)
— default:
false
—

If set, the exchange is deleted when all queues have finished
using it. The server waits for a short period of time before
determining the exchange is unused to give time to the client code
to bind a queue to it.

:internal(Boolean)
— default:
default false
—

If set, the exchange may not be used directly by publishers, but
only when bound to other exchanges. Internal exchanges are used to
construct wiring that is not visible to applications. This is a RabbitMQ-specific
extension.

:nowait(Boolean)
— default:
true
—

If set, the server will not respond to the method. The client should
not wait for a reply method. If the server could not complete the
method it will raise a channel or connection exception.

# open up a channel
# declare a fanout exchange
# declare 3 queues, binds them
# publish a message

Parameters:

name(String)(defaults to: 'amq.fanout')
—

(amq.fanout) Exchange name.

opts(Hash)(defaults to: {})
—

a customizable set of options

Options Hash (opts):

:passive(Boolean)
— default:
false
—

If set, the server will not create the exchange if it does not
already exist. The client can use this to check whether an exchange
exists without modifying the server state.

:durable(Boolean)
— default:
false
—

If set when creating a new exchange, the exchange will be marked as
durable. Durable exchanges and their bindings are recreated upon a server
restart (information about them is persisted). Non-durable (transient) exchanges
do not survive if/when a server restarts (information about them is stored exclusively
in RAM).

:auto_delete(Boolean)
— default:
false
—

If set, the exchange is deleted when all queues have finished
using it. The server waits for a short period of time before
determining the exchange is unused to give time to the client code
to bind a queue to it.

:internal(Boolean)
— default:
default false
—

If set, the exchange may not be used directly by publishers, but
only when bound to other exchanges. Internal exchanges are used to
construct wiring that is not visible to applications. This is a RabbitMQ-specific
extension.

:nowait(Boolean)
— default:
true
—

If set, the server will not respond to the method. The client should
not wait for a reply method. If the server could not complete the
method it will raise a channel or connection exception.

#flow(active = false, &block) ⇒ Object

Asks the peer to pause or restart the flow of content data sent to a consumer.
This is a simple flow­control mechanism that a peer can use to avoid overflowing its
queues or otherwise finding itself receiving more messages than it can process. Note that
this method is not intended for window control. It does not affect contents returned to
Queue#get callers.

#handle_select_ok(method) ⇒ Object

Handler for Confirm.Select-Ok. By default, it just
executes hook specified via the #confirmations method
with a single argument, a protocol method class
instance (an instance of AMQ::Protocol::Confirm::SelectOk)
and then it deletes the callback, since Confirm.Select
is supposed to be sent just once.

If set, the server will not create the exchange if it does not
already exist. The client can use this to check whether an exchange
exists without modifying the server state.

:durable(Boolean)
— default:
false
—

If set when creating a new exchange, the exchange will be marked as
durable. Durable exchanges and their bindings are recreated upon a server
restart (information about them is persisted). Non-durable (transient) exchanges
do not survive if/when a server restarts (information about them is stored exclusively
in RAM).

:auto_delete(Boolean)
— default:
false
—

If set, the exchange is deleted when all queues have finished
using it. The server waits for a short period of time before
determining the exchange is unused to give time to the client code
to bind a queue to it.

:internal(Boolean)
— default:
default false
—

If set, the exchange may not be used directly by publishers, but
only when bound to other exchanges. Internal exchanges are used to
construct wiring that is not visible to applications. This is a RabbitMQ-specific
extension.

:nowait(Boolean)
— default:
true
—

If set, the server will not respond to the method. The client should
not wait for a reply method. If the server could not complete the
method it will raise a channel or connection exception.

Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure).
Only one callback can be defined (the one defined last replaces previously added ones).

#once_open(&block) ⇒ ObjectAlso known as:
once_opened

Takes a block that will be deferred till the moment when channel is considered open
(channel.open-ok is received from the broker). If you need to delay an operation
till the moment channel is open, this method is what you are looking for.

Multiple callbacks are supported. If when this moment is called, channel is already
open, block is executed immediately.

932
933
934
935
936
937
938

# File 'lib/amqp/channel.rb', line 932defonce_open(&block)@channel_is_open_deferrable.callbackdo# guards against cases when deferred operations
# don't complete before the channel is closed
block.callifopen?endend

#open(&block) ⇒ ObjectAlso known as:
reopen

Note:

Instantiated channels are opened by default. This method should only be used for error recovery after network connection loss.

# File 'lib/amqp/channel.rb', line 998defprefetch(count,global=false,&block)self.once_opendo# RabbitMQ does not support prefetch_size.
self.qos(0,count,global,&block)@options[:prefetch]=countendselfend

Declares and returns a Queue instance associated with this channel. See Queue class documentation for
more information about queues.

To make broker generate queue name for you (a classic example is exclusive
queues that are only used for a short period of time), pass empty string
as name value. Then queue will get it’s name as soon as broker’s response
(queue.declare-ok) arrives. Note that in this case, block is required.

Like for exchanges, queue names starting with ‘amq.’ cannot be modified and
should not be used by applications.

Examples:

Declaring a queue in a mail delivery app using Channel#queue without a block

AMQP.connectdo|connection|AMQP::Channel.new(connection)do|ch|# message producers will be able to send messages to this queue
# using direct exchange and routing key = "mail.delivery"
queue=ch.queue("mail.delivery",:durable=>true)queue.subscribedo|headers,payload|# ...
endendend

Declaring a server-named exclusive queue that receives all messages related to events, using a block.

AMQP.connectdo|connection|AMQP::Channel.new(connection)do|ch|# message producers will be able to send messages to this queue
# using amq.topic exchange with routing keys that begin with "events"
ch.queue("",:exclusive=>true)do|queue|queue.bind(ch.exchange("amq.topic"),:routing_key=>"events.#").subscribedo|headers,payload|# ...
endendendend

Parameters:

name(String)(defaults to: AMQ::Protocol::EMPTY_STRING)
—

Queue name. If you want a server-named queue, you can omit the name (note that in this case, using block is mandatory).
See Queue class documentation for discussion of queue lifecycles and when use of server-named queues
is optimal.

opts(Hash)(defaults to: {})
—

a customizable set of options

Options Hash (opts):

:passive(Boolean)
— default:
false
—

If set, the server will not create the exchange if it does not
already exist. The client can use this to check whether an exchange
exists without modifying the server state.

:durable(Boolean)
— default:
false
—

If set when creating a new exchange, the exchange will be marked as
durable. Durable exchanges and their bindings are recreated upon a server
restart (information about them is persisted). Non-durable (transient) exchanges
do not survive if/when a server restarts (information about them is stored exclusively
in RAM). Any remaining messages in the queue will be purged when the queue
is deleted regardless of the message’s persistence setting.

:auto_delete(Boolean)
— default:
false
—

If set, the exchange is deleted when all queues have finished
using it. The server waits for a short period of time before
determining the exchange is unused to give time to the client code
to bind a queue to it.

:exclusive(Boolean)
— default:
false
—

Exclusive queues may only be used by a single connection.
Exclusivity also implies that queue is automatically deleted when connection
is closed. Only one consumer is allowed to remove messages from exclusive queue.

:nowait(Boolean)
— default:
true
—

If set, the server will not respond to the method. The client should
not wait for a reply method. If the server could not complete the
method it will raise a channel or connection exception.

# File 'lib/amqp/channel.rb', line 849defqueue(name=AMQ::Protocol::EMPTY_STRING,opts={},&block)raiseArgumentError.new("queue name must not be nil; if you want broker to generate queue name for you, pass an empty string")ifname.nil?ifname&&!name.empty?&&(queue=find_queue(name))extended_opts=Queue.add_default_options(name,opts,block)validate_parameters_match!(queue,extended_opts,:queue)block.call(queue)ifblockqueueelseself.queue!(name,opts,&block)endend

# File 'lib/amqp/channel.rb', line 341defreuseold_id=@id# must release after we allocate a new id, otherwise we will end up
# with the same value. MK.
@id=@connection.next_channel_id@connection.release_channel_id(old_id)@channel_is_open_deferrable.fail@channel_is_open_deferrable=AMQP::Deferrable.newself.opendo@channel_is_open_deferrable.succeed# re-establish prefetch
self.prefetch(@options[:prefetch],false)if@options[:prefetch]# exchanges must be recovered first because queue recovery includes recovery of bindings. MK.
@exchanges.each{|name,e|e.auto_recover}@queues.each{|name,q|q.auto_recover}endend

If set, the server will not create the exchange if it does not
already exist. The client can use this to check whether an exchange
exists without modifying the server state.

:durable(Boolean)
— default:
false
—

If set when creating a new exchange, the exchange will be marked as
durable. Durable exchanges and their bindings are recreated upon a server
restart (information about them is persisted). Non-durable (transient) exchanges
do not survive if/when a server restarts (information about them is stored exclusively
in RAM).

:auto_delete(Boolean)
— default:
false
—

If set, the exchange is deleted when all queues have finished
using it. The server waits for a short period of time before
determining the exchange is unused to give time to the client code
to bind a queue to it.

:internal(Boolean)
— default:
default false
—

If set, the exchange may not be used directly by publishers, but
only when bound to other exchanges. Internal exchanges are used to
construct wiring that is not visible to applications. This is a RabbitMQ-specific
extension.

:nowait(Boolean)
— default:
true
—

If set, the server will not respond to the method. The client should
not wait for a reply method. If the server could not complete the
method it will raise a channel or connection exception.