def accept(self, n=1, timeout=None): """ Accepts new connections for listening endpoints. Can accept more than one message at at time before it returns a new channel back to the caller. Optionally can specify a timeout - if n messages aren't received in that time, will raise an Empty exception. Sets the channel in the ACCEPTED state - caller is responsible for acking all messages received on the returned channel in order to put this channel back in the CONSUMING state. """ assert self._fsm.current_state in [ self.S_ACTIVE, self.S_CLOSED ], "Channel must be in active/closed state to accept, currently %s (forget to ack messages?)" % str( self._fsm.current_state) was_consuming = self._consuming if not self._should_discard and not was_consuming: # tune QOS to get exactly n messages if not (self._queue_auto_delete and self._transport is AMQPTransport.get_instance()): self._transport.qos_impl(self._amq_chan, prefetch_count=n) # start consuming self.start_consume() with self._recv_queue.await_n(n=n) as ar: log.debug("accept: waiting for %s msgs, timeout=%s", n, timeout) ar.get(timeout=timeout) if not was_consuming: # turn consuming back off if we already were off if not (self._queue_auto_delete and self._transport is AMQPTransport.get_instance()): self.stop_consume() else: log.debug( "accept should turn consume off, but queue is auto_delete and this would destroy the queue" ) ms = [self.recv() for x in xrange(n)] ch = self._create_accepted_channel(self._amq_chan, ms) map(ch._recv_queue.put, ms) # transition to ACCEPT self._fsm.process(self.I_ENTER_ACCEPT) # return the channel return ch
def __init__(self, transport=None, close_callback=None): """ Initializes a BaseChannel instance. @param transport Underlying transport used for broker communication. Can be None, if so, will use the AMQPTransport stateless singleton. @type transport BaseTransport @param close_callback The method to invoke when close() is called on this BaseChannel. May be left as None, in which case close_impl() will be called. This expects to be a callable taking one param, this channel instance. """ self.set_close_callback(close_callback) self._transport = transport or AMQPTransport.get_instance() # setup FSM for BaseChannel / SendChannel tree self._fsm = FSM(self.S_INIT) self._fsm.add_transition(self.I_ATTACH, self.S_INIT, None, self.S_ACTIVE) self._fsm.add_transition(self.I_CLOSE, self.S_ACTIVE, self._on_close, self.S_CLOSED) self._fsm.add_transition( self.I_CLOSE, self.S_CLOSED, None, self.S_CLOSED ) # closed is a goal state, multiple closes are ok and are no-ops self._fsm.add_transition(self.I_CLOSE, self.S_INIT, None, self.S_CLOSED) # INIT to CLOSED is fine too
def test_delete_xn(self): raise unittest.SkipTest("broken 2 mar, skipping for now") # same as the other deletes except with queues instead xn = self.container.ex_manager.create_xn_service('test_service') # prove queue is declared already (can't declare the same named one with diff params) ch = self.container.node.channel(RecvChannel) ch._queue_auto_delete = not xn._xn_auto_delete # must set recv_name ch._recv_name = xn self.assertRaises(TransportError, ch._declare_queue, xn.queue) # now let's delete via ex manager self.container.ex_manager.delete_xn(xn) # grab another channel and declare (should work fine this time) ch = self.container.node.channel(RecvChannel) ch._exchange_auto_delete = not xn._xs._xs_auto_delete # must set recv_name ch._recv_name = xn ch._declare_queue(xn.queue) # cool, now cleanup (we don't expose this via Channel) at = AMQPTransport.get_instance() at.delete_queue_impl(ch._amq_chan, xn.queue)
def close_impl(self): if not self._queue_auto_delete and self._recv_name and self._transport is AMQPTransport.get_instance( ) and self._recv_name.queue.startswith("amq.gen-"): log.debug("Anonymous Subscriber detected, deleting queue (%s)", self._recv_name) self._destroy_queue() ListenChannel.close_impl(self)
def accept(self, n=1, timeout=None): """ Accepts new connections for listening endpoints. Can accept more than one message at at time before it returns a new channel back to the caller. Optionally can specify a timeout - if n messages aren't received in that time, will raise an Empty exception. Sets the channel in the ACCEPTED state - caller is responsible for acking all messages received on the returned channel in order to put this channel back in the CONSUMING state. """ assert self._fsm.current_state in [self.S_ACTIVE, self.S_CLOSED], "Channel must be in active/closed state to accept, currently %s (forget to ack messages?)" % str(self._fsm.current_state) was_consuming = self._consuming if not self._should_discard and not was_consuming: # tune QOS to get exactly n messages if not (self._queue_auto_delete and self._transport is AMQPTransport.get_instance()): self._transport.qos_impl(self._amq_chan, prefetch_count=n) # start consuming self.start_consume() with self._recv_queue.await_n(n=n) as ar: log.debug("accept: waiting for %s msgs, timeout=%s", n, timeout) ar.get(timeout=timeout) if not was_consuming: # turn consuming back off if we already were off if not (self._queue_auto_delete and self._transport is AMQPTransport.get_instance()): self.stop_consume() else: log.debug("accept should turn consume off, but queue is auto_delete and this would destroy the queue") ms = [self.recv() for x in xrange(n)] ch = self._create_accepted_channel(self._amq_chan, ms) map(ch._recv_queue.put, ms) # transition to ACCEPT self._fsm.process(self.I_ENTER_ACCEPT) # return the channel return ch
def start(self): log.debug("ExchangeManager.start") total_count = 0 def handle_failure(name, node): log.warn("Node %s could not be started", name) node.ready.set() # let it fall out below # Establish connection(s) to broker for name, cfgkey in CFG.container.messaging.server.iteritems(): if not cfgkey: continue if cfgkey not in CFG.server: raise ExchangeManagerError("Config key %s (name: %s) (from CFG.container.messaging.server) not in CFG.server" % (cfgkey, name)) total_count += 1 log.debug("Starting connection: %s", name) # start it with a zero timeout so it comes right back to us try: node, ioloop = messaging.make_node(CFG.server[cfgkey], name, 0) # install a finished handler directly on the ioloop just for this startup period fail_handle = lambda _: handle_failure(name, node) ioloop.link(fail_handle) # wait for the node ready event, with a large timeout just in case node_ready = node.ready.wait(timeout=15) # remove the finished handler, we don't care about it here ioloop.unlink(fail_handle) # only add to our list if we started successfully if not node.running: ioloop.kill() # make sure ioloop dead else: self._nodes[name] = node self._ioloops[name] = ioloop except socket.error as e: log.warn("Could not start connection %s due to socket error, continuing", name) fail_count = total_count - len(self._nodes) if fail_count > 0 or total_count == 0: if fail_count == total_count: raise ExchangeManagerError("No node connection was able to start (%d nodes attempted, %d nodes failed)" % (total_count, fail_count)) log.warn("Some nodes could not be started, ignoring for now") # @TODO change when ready self._transport = AMQPTransport.get_instance() # load interceptors into each map(lambda x: x.setup_interceptors(CFG.interceptor), self._nodes.itervalues()) log.debug("Started %d connections (%s)", len(self._nodes), ",".join(self._nodes.iterkeys()))
def __init__(self, transport=None, close_callback=None): """ Initializes a BaseChannel instance. @param transport Underlying transport used for broker communication. Can be None, if so, will use the AMQPTransport stateless singleton. @type transport BaseTransport @param close_callback The method to invoke when close() is called on this BaseChannel. May be left as None, in which case close_impl() will be called. This expects to be a callable taking one param, this channel instance. """ self.set_close_callback(close_callback) self._transport = transport or AMQPTransport.get_instance()
def start(self): log.debug("ExchangeManager starting ...") # Establish connection to broker # @TODO: raise error if sux node, ioloop = messaging.make_node() self._transport = AMQPTransport.get_instance() self._client = self._get_channel(node) # Declare root exchange #self.default_xs.ensure_exists(self._get_channel()) return node, ioloop
def _on_stop_consume(self): """ Stops consuming messages. If the queue has auto_delete, this will delete it. """ #log.debug("RecvChannel._on_stop_consume") if self._queue_auto_delete and self._transport is AMQPTransport.get_instance(): log.debug("Autodelete is on, this will destroy this queue: %s", self._recv_name.queue) self._ensure_amq_chan() self._sync_call(self._amq_chan.basic_cancel, 'callback', self._consumer_tag)
def _on_stop_consume(self): """ Stops consuming messages. If the queue has auto_delete, this will delete it. """ #log.debug("RecvChannel._on_stop_consume") if self._queue_auto_delete and self._transport is AMQPTransport.get_instance( ): log.debug("Autodelete is on, this will destroy this queue: %s", self._recv_name.queue) self._ensure_amq_chan() self._sync_call(self._amq_chan.basic_cancel, 'callback', self._consumer_tag)
def _on_start_consume(self): """ Starts consuming messages. setup_listener must have been called first. """ #log.debug("RecvChannel._on_start_consume") if self._consumer_tag and (self._queue_auto_delete and self._transport is AMQPTransport.get_instance()): log.warn("Attempting to start consuming on a queue that may have been auto-deleted") self._ensure_amq_chan() self._consumer_tag = self._amq_chan.basic_consume(self._on_deliver, queue=self._recv_name.queue, no_ack=self._consumer_no_ack, exclusive=self._consumer_exclusive)
def __init__(self, transport=None, close_callback=None): """ Initializes a BaseChannel instance. @param transport Underlying transport used for broker communication. Can be None, if so, will use the AMQPTransport stateless singleton. @type transport BaseTransport @param close_callback The method to invoke when close() is called on this BaseChannel. May be left as None, in which case close_impl() will be called. This expects to be a callable taking one param, this channel instance. """ self.set_close_callback(close_callback) self._transport = transport or AMQPTransport.get_instance() # setup FSM for BaseChannel / SendChannel tree self._fsm = FSM(self.S_INIT) self._fsm.add_transition(self.I_ATTACH, self.S_INIT, None, self.S_ACTIVE) self._fsm.add_transition(self.I_CLOSE, self.S_ACTIVE, self._on_close, self.S_CLOSED) self._fsm.add_transition(self.I_CLOSE, self.S_CLOSED, None, self.S_CLOSED) # closed is a goal state, multiple closes are ok and are no-ops self._fsm.add_transition(self.I_CLOSE, self.S_INIT, None, self.S_CLOSED) # INIT to CLOSED is fine too
def _on_start_consume(self): """ Starts consuming messages. setup_listener must have been called first. """ #log.debug("RecvChannel._on_start_consume") if self._consumer_tag and (self._queue_auto_delete and self._transport is AMQPTransport.get_instance()): log.warn( "Attempting to start consuming on a queue that may have been auto-deleted" ) self._ensure_amq_chan() self._consumer_tag = self._amq_chan.basic_consume( self._on_deliver, queue=self._recv_name.queue, no_ack=self._consumer_no_ack, exclusive=self._consumer_exclusive)
def test_delete_xp(self): # same as test_delete_xs xp = self.container.ex_manager.create_xp('test_xp') # prove XS is declared already (can't declare the same named one with diff params) ch = self.container.node.channel(RecvChannel) ch._exchange_auto_delete = not xp._xs._xs_auto_delete self.assertRaises(TransportError, ch._declare_exchange, xp.exchange) # now let's delete via ex manager self.container.ex_manager.delete_xp(xp) # grab another channel and declare (should work fine this time) ch = self.container.node.channel(RecvChannel) ch._exchange_auto_delete = not xp._xs._xs_auto_delete ch._declare_exchange(xp.exchange) # cool, now cleanup (we don't expose this via Channel) at = AMQPTransport.get_instance() at.delete_exchange_impl(ch._amq_chan, xp.exchange)
def test_delete_xs(self): # we get interesting here. we have to create or xs, try to declare again to prove it is there, # then delete, then declare to prove we CAN create, then make sure to clean it up. whew. xs = self.container.ex_manager.create_xs('test_xs') # prove XS is declared already (can't declare the same named one with diff params) ch = self.container.node.channel(RecvChannel) ch._exchange_auto_delete = not xs._xs_auto_delete self.assertRaises(TransportError, ch._declare_exchange, xs.exchange) # now let's delete via ex manager self.container.ex_manager.delete_xs(xs) # grab another channel and declare (should work fine this time) ch = self.container.node.channel(RecvChannel) ch._exchange_auto_delete = not xs._xs_auto_delete ch._declare_exchange(xs.exchange) # cool, now cleanup (we don't expose this via Channel) at = AMQPTransport.get_instance() at.delete_exchange_impl(ch._amq_chan, xs.exchange)
def close_impl(self): if not self._queue_auto_delete and self._recv_name and self._transport is AMQPTransport.get_instance() and self._recv_name.queue.startswith("amq.gen-"): log.debug("Anonymous Subscriber detected, deleting queue (%s)", self._recv_name) self._destroy_queue() ListenChannel.close_impl(self)