Included Modules

Class Index [+]

Quicksearch

AMQ::Client::Async::Adapter

Base adapter class. Specific implementations (for example, EventMachine-based, Cool.io-based or sockets-based) subclass it and must implement Adapter API methods:

@abstract

Public Class Methods

included(host) click to toggle source
     # File lib/amq/client/async/adapter.rb, line 23
 23:         def self.included(host)
 24:           host.extend ClassMethods
 25:           host.extend ProtocolMethodHandlers
 26: 
 27:           host.class_eval do
 28: 
 29:             #
 30:             # API
 31:             #
 32: 
 33:             attr_accessor :logger
 34:             attr_accessor :settings
 35: 
 36:             # @return [Array<#call>]
 37:             attr_reader :callbacks
 38: 
 39: 
 40:             # The locale defines the language in which the server will send reply texts.
 41:             #
 42:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2)
 43:             attr_accessor :locale
 44: 
 45:             # Client capabilities
 46:             #
 47:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2.1)
 48:             attr_accessor :client_properties
 49: 
 50:             # Server properties
 51:             #
 52:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.3)
 53:             attr_reader :server_properties
 54: 
 55:             # Server capabilities
 56:             #
 57:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.3)
 58:             attr_reader :server_capabilities
 59: 
 60:             # Locales server supports
 61:             #
 62:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.3)
 63:             attr_reader :server_locales
 64: 
 65:             # Authentication mechanism used.
 66:             #
 67:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2)
 68:             attr_reader :mechanism
 69: 
 70:             # Authentication mechanisms broker supports.
 71:             #
 72:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2)
 73:             attr_reader :server_authentication_mechanisms
 74: 
 75:             # Channels within this connection.
 76:             #
 77:             # @see http://bit.ly/amqp091spec AMQP 0.9.1 specification (Section 2.2.5)
 78:             attr_reader :channels
 79: 
 80:             # Maximum channel number that the server permits this connection to use.
 81:             # Usable channel numbers are in the range 1..channel_max.
 82:             # Zero indicates no specified limit.
 83:             #
 84:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Sections 1.4.2.5.1 and 1.4.2.6.1)
 85:             attr_accessor :channel_max
 86: 
 87:             # Maximum frame size that the server permits this connection to use.
 88:             #
 89:             # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Sections 1.4.2.5.2 and 1.4.2.6.2)
 90:             attr_accessor :frame_max
 91: 
 92: 
 93:             attr_reader :known_hosts
 94: 
 95: 
 96: 
 97:             # @api plugin
 98:             # @see #disconnect
 99:             # @note Adapters must implement this method but it is NOT supposed to be used directly.
100:             #       AMQ protocol defines two-step process of closing connection (send Connection.Close
101:             #       to the peer and wait for Connection.Close-Ok), implemented by {Adapter#disconnect}
102:             def close_connection
103:               raise NotImplementedError
104:             end unless defined?(:close_connection) # since it is a module, this method may already be defined
105:           end
106:         end

Public Instance Methods

after_connection_interruption(&block) click to toggle source
after_recovery(&block) click to toggle source
Alias for: on_recovery
auto_recover() click to toggle source

Performs recovery of channels that are in the automatic recovery mode. Does not run recovery callbacks.

@see Channel#auto_recover @see Queue#auto_recover @see Exchange#auto_recover @api plugin

     # File lib/amq/client/async/adapter.rb, line 420
420:         def auto_recover
421:           @channels.select { |channel_id, ch| ch.auto_recovering? }.each { |n, ch| ch.auto_recover }
422:         end
auto_recovering?() click to toggle source

@return [Boolean] whether connection is in the automatic recovery mode @api public

     # File lib/amq/client/async/adapter.rb, line 407
407:         def auto_recovering?
408:           !!@auto_recovery
409:         end
Also aliased as: auto_recovery?
auto_recovery?() click to toggle source
Alias for: auto_recovering?
before_recovery(&block) click to toggle source

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).

@api public

     # File lib/amq/client/async/adapter.rb, line 376
376:         def before_recovery(&block)
377:           self.redefine_callback(:before_recovery, &block)
378:         end
clear_frames_on(channel_id) click to toggle source

Clears frames that were received but not processed on given channel. Needs to be called when the channel is closed. @private

     # File lib/amq/client/async/adapter.rb, line 549
549:         def clear_frames_on(channel_id)
550:           raise ArgumentError, "channel id cannot be nil!" if channel_id.nil?
551: 
552:           @frames[channel_id].clear
553:         end
close_connection() click to toggle source

@api plugin @see # @note Adapters must implement this method but it is NOT supposed to be used directly.

      AMQ protocol defines two-step process of closing connection (send Connection.Close
      to the peer and wait for Connection.Close-Ok), implemented by {Adapter#disconnect}
     # File lib/amq/client/async/adapter.rb, line 102
102:             def close_connection
103:               raise NotImplementedError
104:             end
disconnect(reply_code = 200, reply_text = "Goodbye", class_id = 0, method_id = 0, &block) click to toggle source

Properly close connection with AMQ broker, as described in section 2.2.4 of the {bit.ly/amqp091spec AMQP 0.9.1 specification}.

@api plugin @see #

     # File lib/amq/client/async/adapter.rb, line 212
212:         def disconnect(reply_code = 200, reply_text = "Goodbye", class_id = 0, method_id = 0, &block)
213:           @intentionally_closing_connection = true
214:           self.on_disconnection do
215:             @frames.clear
216:             block.call if block
217:           end
218: 
219:           # ruby-amqp/amqp#66, MK.
220:           if self.open?
221:             closing!
222:             self.send_frame(Protocol::Connection::Close.encode(reply_code, reply_text, class_id, method_id))
223:           elsif self.closing?
224:             # no-op
225:           else
226:             self.disconnection_successful
227:           end
228:         end
encode_credentials(username, password) click to toggle source

@api plugin @see tools.ietf.org/rfc/rfc2595.txt RFC 2595

     # File lib/amq/client/async/adapter.rb, line 505
505:         def encode_credentials(username, password)
506:           "\00##{username}\00##{password}"
507:         end
establish_connection(settings) click to toggle source

Establish socket connection to the server.

@api plugin

     # File lib/amq/client/async/adapter.rb, line 203
203:         def establish_connection(settings)
204:           raise NotImplementedError
205:         end
handle_close(conn_close) click to toggle source

Handles connection.close. When broker detects a connection level exception, this method is called.

@api plugin @see bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.5.2.9)

     # File lib/amq/client/async/adapter.rb, line 624
624:         def handle_close(conn_close)
625:           closed!
626:           self.exec_callback_yielding_self(:error, conn_close)
627:         end
handle_close_ok(close_ok) click to toggle source

Handles Connection.Close-Ok.

@api plugin @see bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.10)

     # File lib/amq/client/async/adapter.rb, line 634
634:         def handle_close_ok(close_ok)
635:           closed!
636:           self.disconnection_successful
637:         end
handle_connection_interruption() click to toggle source

@private @api plugin

     # File lib/amq/client/async/adapter.rb, line 364
364:         def handle_connection_interruption
365:           @channels.each { |n, c| c.handle_connection_interruption }
366:           self.exec_callback_yielding_self(:after_connection_interruption)
367:         end
handle_open_ok(open_ok) click to toggle source

Handles Connection.Open-Ok.

@api plugin @see bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.8.)

     # File lib/amq/client/async/adapter.rb, line 612
612:         def handle_open_ok(open_ok)
613:           @known_hosts = open_ok.known_hosts.dup.freeze
614: 
615:           opened!
616:           self.connection_successful if self.respond_to?(:connection_successful)
617:         end
handle_start(connection_start) click to toggle source

Handles connection.start.

@api plugin @see bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.)

     # File lib/amq/client/async/adapter.rb, line 576
576:         def handle_start(connection_start)
577:           @server_properties                = connection_start.server_properties
578:           @server_capabilities              = @server_properties["capabilities"]
579: 
580:           @server_authentication_mechanisms = (connection_start.mechanisms || "").split(" ")
581:           @server_locales                   = Array(connection_start.locales)
582: 
583:           username = @settings[:user] || @settings[:username]
584:           password = @settings[:pass] || @settings[:password]
585: 
586:           # It's not clear whether we should transition to :opening state here
587:           # or in #open but in case authentication fails, it would be strange to have
588:           # @status undefined. So lets do this. MK.
589:           opening!
590: 
591:           self.send_frame(Protocol::Connection::StartOk.encode(@client_properties, @mechanism, self.encode_credentials(username, password), @locale))
592:         end
handle_tune(tune_ok) click to toggle source

Handles Connection.Tune-Ok.

@api plugin @see bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6)

     # File lib/amq/client/async/adapter.rb, line 599
599:         def handle_tune(tune_ok)
600:           @channel_max        = tune_ok.channel_max.freeze
601:           @frame_max          = tune_ok.frame_max.freeze
602:           @heartbeat_interval = self.heartbeat_interval || tune_ok.heartbeat
603: 
604:           self.send_frame(Protocol::Connection::TuneOk.encode(@channel_max, [settings[:frame_max], @frame_max].min, @heartbeat_interval))
605:         end
handshake() click to toggle source

Sends connection preamble to the broker. @api plugin

     # File lib/amq/client/async/adapter.rb, line 482
482:         def handshake
483:           @authenticating = true
484:           self.send_preamble
485:         end
heartbeat_interval() click to toggle source

Returns heartbeat interval this client uses, in seconds. This value may or may not be used depending on broker capabilities. Zero means the server does not want a heartbeat.

@return [Fixnum] Heartbeat interval this client uses, in seconds. @see bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6)

     # File lib/amq/client/async/adapter.rb, line 276
276:         def heartbeat_interval
277:           @settings[:heartbeat] || @settings[:heartbeat_interval] || 0
278:         end
on_connection_interruption(&block) click to toggle source

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).

@api public

     # File lib/amq/client/async/adapter.rb, line 356
356:         def on_connection_interruption(&block)
357:           self.redefine_callback(:after_connection_interruption, &block)
358:         end
on_error(&block) click to toggle source

Defines a callback that will be executed when connection is closed after connection-level exception. Only one callback can be defined (the one defined last replaces previously added ones).

@api public

     # File lib/amq/client/async/adapter.rb, line 347
347:         def on_error(&block)
348:           self.redefine_callback(:error, &block)
349:         end
on_possible_authentication_failure(&block) click to toggle source

Defines a callback that will be run when TCP connection is closed before authentication finishes. Usually this means authentication failure. You can define only one callback.

@api public

     # File lib/amq/client/async/adapter.rb, line 337
337:         def on_possible_authentication_failure(&block)
338:           @on_possible_authentication_failure = block
339:         end
on_recovery(&block) click to toggle source

Defines a callback that will be executed after AMQP connection has recovered after a network failure.. Only one callback can be defined (the one defined last replaces previously added ones).

@api public

     # File lib/amq/client/async/adapter.rb, line 392
392:         def on_recovery(&block)
393:           self.redefine_callback(:after_recovery, &block)
394:         end
Also aliased as: after_recovery
on_skipped_heartbeats(&block) click to toggle source

Defines a callback that will be executed after time since last broker heartbeat is greater than or equal to the heartbeat interval (skipped heartbeat is detected). Only one callback can be defined (the one defined last replaces previously added ones).

@api public

     # File lib/amq/client/async/adapter.rb, line 453
453:         def on_skipped_heartbeats(&block)
454:           self.redefine_callback(:skipped_heartbeats, &block)
455:         end
on_tcp_connection_failure(&block) click to toggle source

Defines a callback that will be run when initial TCP connection fails. You can define only one callback.

@api public

     # File lib/amq/client/async/adapter.rb, line 321
321:         def on_tcp_connection_failure(&block)
322:           @on_tcp_connection_failure = block
323:         end
on_tcp_connection_loss(&block) click to toggle source

Defines a callback that will be run when TCP connection to AMQP broker is lost (interrupted). You can define only one callback.

@api public

     # File lib/amq/client/async/adapter.rb, line 329
329:         def on_tcp_connection_loss(&block)
330:           @on_tcp_connection_loss = block
331:         end
open(vhost = "/") click to toggle source

Sends connection.open to the server.

@api plugin @see bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.7)

     # File lib/amq/client/async/adapter.rb, line 492
492:         def open(vhost = "/")
493:           self.send_frame(Protocol::Connection::Open.encode(vhost))
494:         end
receive_frame(frame) click to toggle source

Processes a single frame.

@param [AMQ::Protocol::Frame] frame @api plugin

     # File lib/amq/client/async/adapter.rb, line 514
514:         def receive_frame(frame)
515:           @frames[frame.channel] ||= Array.new
516:           @frames[frame.channel] << frame
517: 
518:           if frameset_complete?(@frames[frame.channel])
519:             receive_frameset(@frames[frame.channel])
520:             # for channel.close, frame.channel will be nil. MK.
521:             clear_frames_on(frame.channel) if @frames[frame.channel]
522:           end
523:         end
receive_frameset(frames) click to toggle source

Processes a frameset by finding and invoking a suitable handler. Heartbeat frames are treated in a special way: they simply update @last_server_heartbeat value.

@param [Array] frames @api plugin

     # File lib/amq/client/async/adapter.rb, line 531
531:         def receive_frameset(frames)
532:           frame = frames.first
533: 
534:           if Protocol::HeartbeatFrame === frame
535:             @last_server_heartbeat = Time.now
536:           else
537:             if callable = AMQ::Client::HandlersRegistry.find(frame.method_class)
538:               f = frames.shift
539:               callable.call(self, f, frames)
540:             else
541:               raise MissingHandlerError.new(frames.first)
542:             end
543:           end
544:         end
reconnecting?() click to toggle source

@return [Boolean]

     # File lib/amq/client/async/adapter.rb, line 312
312:         def reconnecting?
313:           @reconnecting
314:         end
reset_state!() click to toggle source

Resets connection state.

@api plugin

     # File lib/amq/client/async/adapter.rb, line 499
499:         def reset_state!
500:           # no-op by default
501:         end
run_after_recovery_callbacks() click to toggle source

@private

     # File lib/amq/client/async/adapter.rb, line 398
398:         def run_after_recovery_callbacks
399:           self.exec_callback_yielding_self(:after_recovery, @settings)
400: 
401:           @channels.each { |n, ch| ch.run_after_recovery_callbacks }
402:         end
run_before_recovery_callbacks() click to toggle source

@private

     # File lib/amq/client/async/adapter.rb, line 381
381:         def run_before_recovery_callbacks
382:           self.exec_callback_yielding_self(:before_recovery, @settings)
383: 
384:           @channels.each { |n, ch| ch.run_before_recovery_callbacks }
385:         end
run_skipped_heartbeats_callbacks() click to toggle source

@private

     # File lib/amq/client/async/adapter.rb, line 458
458:         def run_skipped_heartbeats_callbacks
459:           self.exec_callback_yielding_self(:skipped_heartbeats, @settings)
460:         end
send_frame(frame) click to toggle source

Sends frame to the peer, checking that connection is open.

@raise [ConnectionClosedError]

     # File lib/amq/client/async/adapter.rb, line 245
245:         def send_frame(frame)
246:           if closed?
247:             raise ConnectionClosedError.new(frame)
248:           else
249:             self.send_raw(frame.encode)
250:           end
251:         end
send_frameset(frames, channel) click to toggle source

Sends multiple frames, one by one. For thread safety this method takes a channel object and synchronizes on it.

@api public

     # File lib/amq/client/async/adapter.rb, line 257
257:         def send_frameset(frames, channel)
258:           # some (many) developers end up sharing channels between threads and when multiple
259:           # threads publish on the same channel aggressively, at some point frames will be
260:           # delivered out of order and broker will raise 505 UNEXPECTED_FRAME exception.
261:           # If we synchronize on the channel, however, this is both thread safe and pretty fine-grained
262:           # locking. Note that "single frame" methods do not need this kind of synchronization. MK.
263:           channel.synchronize do
264:             frames.each { |frame| self.send_frame(frame) }
265:           end
266:         end
send_heartbeat() click to toggle source

Sends a heartbeat frame if connection is open. @api plugin

     # File lib/amq/client/async/adapter.rb, line 557
557:         def send_heartbeat
558:           if tcp_connection_established? && !@handling_skipped_hearbeats
559:             if @last_server_heartbeat < (Time.now - (self.heartbeat_interval * 2)) && !reconnecting?
560:               logger.error "[amqp] Detected missing server heartbeats"
561:               self.handle_skipped_hearbeats
562:             end
563:             send_frame(Protocol::HeartbeatFrame)
564:           end
565:         end
send_preamble() click to toggle source

Sends AMQ protocol header (also known as preamble).

@note This must be implemented by all AMQP clients. @api plugin @see bit.ly/amqp091spec AMQP 0.9.1 specification (Section 2.2)

     # File lib/amq/client/async/adapter.rb, line 238
238:         def send_preamble
239:           self.send_raw(AMQ::Protocol::PREAMBLE)
240:         end
send_raw(data) click to toggle source

Sends opaque data to AMQ broker over active connection.

@note This must be implemented by all AMQP clients. @api plugin

     # File lib/amq/client/async/adapter.rb, line 476
476:         def send_raw(data)
477:           raise NotImplementedError
478:         end
start_automatic_recovery() click to toggle source

Performs recovery of channels that are in the automatic recovery mode. “before recovery” callbacks are run immediately, “after recovery” callbacks are run after AMQP connection is re-established and auto recovery is performed (using #).

Use this method if you want to run automatic recovery process after handling a connection-level exception, for example, 320 CONNECTION_FORCED (used by RabbitMQ when it is shut down gracefully).

@see Channel#auto_recover @see Queue#auto_recover @see Exchange#auto_recover @api plugin

     # File lib/amq/client/async/adapter.rb, line 436
436:         def start_automatic_recovery
437:           self.run_before_recovery_callbacks
438:           self.register_connection_callback do
439:             # always run automatic recovery, because it is per-channel
440:             # and connection has to start it. Channels that did not opt-in for
441:             # autorecovery won't be selected. MK.
442:             self.auto_recover
443:             self.run_after_recovery_callbacks
444:           end
445:         end
tcp_connection_failed() click to toggle source

Called when initial TCP connection fails. @api public

     # File lib/amq/client/async/adapter.rb, line 296
296:         def tcp_connection_failed
297:           @recovered = false
298: 
299:           @on_tcp_connection_failure.call(@settings) if @on_tcp_connection_failure
300:         end
tcp_connection_lost() click to toggle source

Called when previously established TCP connection fails. @api public

     # File lib/amq/client/async/adapter.rb, line 304
304:         def tcp_connection_lost
305:           @recovered = false
306: 
307:           @on_tcp_connection_loss.call(self, @settings) if @on_tcp_connection_loss
308:           self.handle_connection_interruption
309:         end
vhost() click to toggle source

vhost this connection uses. Default is “/”, a historically estabilished convention of RabbitMQ and amqp gem.

@return [String] vhost this connection uses @api public

     # File lib/amq/client/async/adapter.rb, line 286
286:         def vhost
287:           @settings.fetch(:vhost, "/")
288:         end

Protected Instance Methods

content_complete?(frames) click to toggle source

Determines, whether given frame array contains full content body

     # File lib/amq/client/async/adapter.rb, line 671
671:         def content_complete?(frames)
672:           return false if frames.empty?
673:           header = frames[0]
674:           raise "Not a content header frame first: #{header.inspect}" unless header.kind_of?(AMQ::Protocol::HeaderFrame)
675:           header.body_size == frames[1..1].inject(0) {|sum, frame| sum + frame.payload.size }
676:         end
frameset_complete?(frames) click to toggle source

Determines, whether the received frameset is ready to be further processed

     # File lib/amq/client/async/adapter.rb, line 664
664:         def frameset_complete?(frames)
665:           return false if frames.empty?
666:           first_frame = frames[0]
667:           first_frame.final? || (first_frame.method_class.has_content? && content_complete?(frames[1..1]))
668:         end
get_next_frame() click to toggle source

Returns next frame from buffer whenever possible

@api private

     # File lib/amq/client/async/adapter.rb, line 646
646:         def get_next_frame
647:           return nil unless @chunk_buffer.size > 7 # otherwise, cannot read the length
648:           # octet + short
649:           offset = 3 # 1 + 2
650:           # length
651:           payload_length = @chunk_buffer[offset, 4].unpack(AMQ::Protocol::PACK_UINT32).first
652:           # 4 bytes for long payload length, 1 byte final octet
653:           frame_length = offset + payload_length + 5
654:           if frame_length <= @chunk_buffer.size
655:             @chunk_buffer.slice!(0, frame_length)
656:           else
657:             nil
658:           end
659:         end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.