def test__send(self): ac = Mock(pchannel.Channel) self.ch._amq_chan = ac # test sending in params self.ch._send(NameTrio('xp', 'namen'), 'daten') # get our props self.assertTrue(ac.basic_publish.called) self.assertIn('exchange', ac.basic_publish.call_args[1]) self.assertIn('routing_key', ac.basic_publish.call_args[1]) self.assertIn('body', ac.basic_publish.call_args[1]) self.assertIn('immediate', ac.basic_publish.call_args[1]) self.assertIn('mandatory', ac.basic_publish.call_args[1]) self.assertIn('properties', ac.basic_publish.call_args[1]) props = ac.basic_publish.call_args[1].get('properties') self.assertIsInstance(props, BasicProperties) self.assertTrue(hasattr(props, 'headers')) self.assertEquals(props.headers, {}) # try another call to _send with a header self.ch._send(NameTrio('xp', 'namen'), 'daten', headers={'custom': 'val'}) # make sure our property showed up props = ac.basic_publish.call_args[1].get('properties') self.assertIn('custom', props.headers) self.assertEquals(props.headers['custom'], 'val')
def __init__(self, exchange_manager, exchange, exchange_type='topic', durable=False, auto_delete=True): XOTransport.__init__(self, exchange_manager=exchange_manager) NameTrio.__init__(self, exchange=exchange) self._xs_exchange_type = exchange_type self._xs_durable = durable self._xs_auto_delete = auto_delete
def test__send(self): transport = Mock() transport.channel_number = sentinel.channel_number self.ch.on_channel_open(transport) # test sending in params self.ch._send(NameTrio('xp', 'namen'), 'daten') # get our props self.assertTrue(transport.publish_impl.called) self.assertIn('exchange', transport.publish_impl.call_args[1]) self.assertIn('routing_key', transport.publish_impl.call_args[1]) self.assertIn('body', transport.publish_impl.call_args[1]) self.assertIn('immediate', transport.publish_impl.call_args[1]) self.assertIn('mandatory', transport.publish_impl.call_args[1]) self.assertIn('properties', transport.publish_impl.call_args[1]) props = transport.publish_impl.call_args[1].get('properties') self.assertEquals(props, {}) # try another call to _send with a header self.ch._send(NameTrio('xp', 'namen'), 'daten', headers={'custom': 'val'}) # make sure our property showed up props = transport.publish_impl.call_args[1].get('properties') self.assertIn('custom', props) self.assertEquals(props['custom'], 'val')
def __init__(self, exchange_manager, priviledged_transport, name, xs, durable=None, auto_delete=None): XOTransport.__init__(self, exchange_manager=exchange_manager, priviledged_transport=priviledged_transport) NameTrio.__init__(self, exchange=None, queue=name) self._xs = xs if durable is not None: self._xn_durable = durable if auto_delete is not None: self._xn_auto_delete = auto_delete
def __init__(self, exchange_manager, name, xs, xptype=None): xptype = xptype or 'ttree' XOTransport.__init__(self, exchange_manager=exchange_manager) NameTrio.__init__(self, exchange=name) self._xs = xs self._xptype = xptype
def __init__(self, exchange_manager, name, xs, durable=None, auto_delete=None): XOTransport.__init__(self, exchange_manager=exchange_manager) NameTrio.__init__(self, exchange=None, queue=name) self._xs = xs if durable: self._xn_durable = durable if auto_delete: self._xn_auto_delete = auto_delete
def __init__(self, exchange_manager, name, xs, durable=None, auto_delete=None): XOTransport.__init__(self, exchange_manager=exchange_manager) NameTrio.__init__(self, exchange=None, queue=name) self._xs = xs if durable is not None: self._xn_durable = durable if auto_delete is not None: self._xn_auto_delete = auto_delete
def __init__(self, exchange_manager, privileged_transport, node, name, xs, xptype=None): xptype = xptype or "ttree" XOTransport.__init__( self, exchange_manager=exchange_manager, privileged_transport=privileged_transport, node=node ) NameTrio.__init__(self, exchange=name) self._xs = xs self._xptype = xptype
def __init__(self, exchange_manager, privileged_transport, node, name, xs, xptype=None): xptype = xptype or 'ttree' XOTransport.__init__(self, exchange_manager=exchange_manager, privileged_transport=privileged_transport, node=node) NameTrio.__init__(self, exchange=name) self._xs = xs self._xptype = xptype
def test_setup_listener_existing_recv_name_with_differing_name(self): ch = self._create_channel() recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding) ch._recv_name = recv_name ch.setup_listener( name=NameTrio(sentinel.xp, sentinel.queue, sentinel.notbinding)) self.assertNotEquals(ch._recv_name, recv_name) self.assertEquals(ch._recv_name.exchange, sentinel.xp) self.assertEquals(ch._recv_name.queue, sentinel.queue) self.assertEquals(ch._recv_name.binding, sentinel.notbinding)
def __init__(self, node=None, name=None, from_name=None, binding=None): BaseEndpoint.__init__(self, node=node) if name: log.warn("ListeningBaseEndpoint: name param is deprecated, please use from_name instead") self._recv_name = from_name or name # ensure NameTrio if not isinstance(self._recv_name, NameTrio): self._recv_name = NameTrio(bootstrap.get_sys_name(), self._recv_name, binding) # if _recv_name is tuple it takes precedence self._ready_event = event.Event() self._binding = binding
def on_start(self): TransformDataProcess.on_start(self) # set up subscriber to * self._bt_sub = Subscriber(callback=lambda m, h: self.call_process(m), from_name=NameTrio(get_sys_name(), 'bench_queue', '*')) # spawn listener self._sub_gl = spawn(self._bt_sub.listen) # set up publisher to anything! self._bt_pub = Publisher(to_name=NameTrio(get_sys_name(), str(uuid.uuid4())[0:6]))
def _unbind_subscription(self, exchange_point, exchange_name, routing_key): try: channel = self.container.node.channel(BindingChannel) channel._recv_name = NameTrio(exchange_point, exchange_name) channel._recv_name = NameTrio( channel._recv_name.exchange, '.'.join([exchange_point, exchange_name])) channel._recv_binding = routing_key channel._destroy_binding() except TransportError, te: log.exception( 'Raised transport error during deactivate_subscription. Assuming that it is due to deleting a binding that was already deleted and continuing!' )
def _bind_subscription(self, exchange_point, exchange_name, routing_key): try: channel = self.container.node.channel(BindingChannel) channel.setup_listener(NameTrio(exchange_point, exchange_name), binding=routing_key) except TransportError: log.exception( 'Caught Transport Error while creating a binding. Trying Subscriber Binding to make the queue first' ) channel = self.container.node.channel(SubscriberChannel) channel.setup_listener(NameTrio(exchange_point, exchange_name), binding=routing_key)
def test_listen_exception_in_handling(self): # make a listen loop that will return one message (to blow up in processing) chmock = MagicMock(spec=ListenChannel) chmock.accept.return_value = Mock() chmock.accept.return_value.recv = Mock( return_value=(sentinel.msg, sentinel.headers, sentinel.delivery_tag)) chmock.accept.return_value._recv_queue.qsize.return_value = 1 nodemock = Mock(spec=NodeB) nodemock.channel.return_value = chmock recv_name = NameTrio(sentinel.ex, sentinel.queue) ep = ListeningBaseEndpoint(node=nodemock, from_name=recv_name) # make msg received error out! ep.create_endpoint = Mock(return_value=Mock(spec=EndpointUnit)) ep.create_endpoint.return_value._message_received.side_effect = TestError ep.create_endpoint.return_value.intercept_in.return_value = ( sentinel.msg, sentinel.headers) self.assertRaises(TestError, ep.listen) chmock.setup_listener.assert_called_once_with(recv_name, binding=sentinel.queue) chmock.start_consume.assert_called_once_with() chmock.accept.assert_called_once_with(n=1, timeout=None) chmock.accept.return_value.recv.assert_called_once_with() ep.create_endpoint.assert_called_once_with( existing_channel=chmock.accept.return_value)
def _create_accepted_channel(self, amq_chan, msg): send_name = NameTrio(tuple(msg[1].get('reply-to').split(','))) # @TODO: stringify is not the best ch = self.BidirAcceptChannel() ch._recv_name = self._recv_name # for debugging only ch.attach_underlying_channel(amq_chan) ch.connect(send_name) return ch
def test_purge(self): # declare both ex and queue self.transport.declare_exchange_impl(self.ex_name) self.transport.declare_queue_impl(self.queue_name) self.addCleanup(self.transport.delete_queue_impl, self.queue_name) #self.addCleanup(self.container.ex_manager.delete_exchange, self.ex_name) #@TODO exchange AD takes care of this when delete of queue # declare a bind self.transport.bind_impl(self.ex_name, self.queue_name, self.bind_name) # deliver some messages ch = self.container.node.channel(SendChannel) ch._send_name = NameTrio(self.ex_name, self.bind_name) ch.send('one') ch.send('two') ch.close() # should have two messages after routing happens (non-deterministic) time.sleep(2) queue_info = self.container.ex_manager.get_queue_info(self.queue_name) self.assertEquals(queue_info['messages'], 2) # now purge it self.transport.purge_impl(self.queue_name) time.sleep(2) queue_info = self.container.ex_manager.get_queue_info(self.queue_name) self.assertEquals(queue_info['messages'], 0)
def _send(self, msg, headers=None, **kwargs): # could have a specified timeout in kwargs if 'timeout' in kwargs and kwargs['timeout'] is not None: timeout = kwargs['timeout'] else: timeout = CFG.endpoint.receive.timeout or 10 log.debug("RequestEndpointUnit.send (timeout: %s)", timeout) if not self._recv_greenlet: self.channel.setup_listener(NameTrio(self.channel._send_name.exchange)) # anon queue self.channel.start_consume() self.spawn_listener() self.response_queue = event.AsyncResult() self.message_received = lambda m, h: self.response_queue.set((m, h)) BidirectionalEndpointUnit._send(self, msg, headers=headers) try: result_data, result_headers = self.response_queue.get(timeout=timeout) except Timeout: raise exception.Timeout('Request timed out (%d sec) waiting for response from %s' % (timeout, str(self.channel._send_name))) log.debug("Got response to our request: %s, headers: %s", result_data, result_headers) return result_data, result_headers
def test_str(self): nt = NameTrio(sentinel.exchange, sentinel.queue, sentinel.binding) strnt = str(nt) self.assertIn(str(sentinel.exchange), strnt) self.assertIn(str(sentinel.queue), strnt) self.assertIn(str(sentinel.binding), strnt)
def launch_benchmark(transform_number=1, primer=1, message_length=4): import gevent from gevent.greenlet import Greenlet from pyon.util.containers import DotDict from pyon.net.transport import NameTrio from pyon.net.endpoint import Publisher import uuid num = transform_number msg_len = message_length transforms = list() pids = 1 TransformBenchTesting.message_length = message_length cc = Container.instance pub = Publisher(to_name=NameTrio(get_sys_name(), str(uuid.uuid4())[0:6])) for i in xrange(num): tbt = cc.proc_manager._create_service_instance( str(pids), 'tbt', 'prototype.transforms.linear', 'TransformInPlace', DotDict({ 'process': { 'name': 'tbt%d' % pids, 'transform_id': pids } })) tbt.init() tbt.start() gevent.sleep(0.2) for i in xrange(primer): pub.publish(list(xrange(msg_len))) g = Greenlet(tbt.perf) g.start() transforms.append(tbt) pids += 1
def listen(lch): """ The purpose of the this listen method is to trigger waits in code below. By setting up a listener that subscribes to both 3 and 5, and putting received messages into the appropriate gevent-queues client side, we can assume that the channel we're actually testing with get_stats etc has had the message delivered too. """ lch._queue_auto_delete = False lch.setup_listener( NameTrio(bootstrap.get_sys_name(), 'alternate_listener'), 'routed.3') lch._bind('routed.5') lch.start_consume() while True: try: with lch.accept() as newchan: m, h, d = newchan.recv() count = m.rsplit(',', 1)[-1] if m.startswith('5,'): self.five_events.put(int(count)) newchan.ack(d) elif m.startswith('3,'): self.three_events.put(int(count)) newchan.ack(d) else: raise StandardError("unknown message: %s" % m) except ChannelClosedError: break
def test_connect(self): self.ch.connect(NameTrio('xp', 'key')) self.assertTrue(hasattr(self.ch._send_name, 'exchange')) self.assertTrue(hasattr(self.ch._send_name, 'queue')) self.assertEquals(self.ch._send_name.exchange, 'xp') self.assertEquals(self.ch._send_name.queue, 'key') self.assertEquals(self.ch._exchange, 'xp')
def test_init_tuples_both(self): # exchange kwarg has priority over queue kwarg nt = NameTrio(exchange=(sentinel.exchange1, ), queue=(sentinel.exchange2, sentinel.queue)) self.assertEquals(nt._exchange, sentinel.exchange1) self.assertEquals(nt._queue, None) self.assertEquals(nt._binding, None)
def _setup_mock_channel(self, ch_type=BidirClientChannel, status_code=200, error_message="no problem", value="bidirmsg", op=None): """ Sets up a mocked channel, ready for fake bidir communication. @param ch_type Channel type the mock should spec to. @param status_code The status code of the operation, relevant only for RR comms. @param error_message The error message of the operation, relevant only for RR comms. @param op The op name, relevant only for RR comms. @param value The msg body to be returned. """ ch = MagicMock(spec=ch_type()) # set a return value for recv so we get an immediate response vals = [(value, { 'status_code': status_code, 'error_message': error_message, 'op': op, 'conv-id': sentinel.conv_id }, sentinel.delivery_tag)] def _ret(*args, **kwargs): if len(vals): return vals.pop() raise ChannelClosedError() ch.recv.side_effect = _ret # need to set a send_name for now ch._send_name = NameTrio('', '') return ch
def test_setup_listener_existing_recv_name(self): ch = self._create_channel() recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding) ch._recv_name = recv_name ch.setup_listener() self.assertEquals(ch._recv_name, recv_name)
def test_close_does_delete_if_anonymous_and_not_auto_delete(self): ch = SubscriberChannel() ch._queue_auto_delete = False ch._destroy_queue = Mock() ch._recv_name = NameTrio(sentinel.exchange, 'amq.gen-ABCD') ch.close_impl() ch._destroy_queue.assert_called_once_with()
def every_three(): p = self.container.node.channel(PublisherChannel) p._send_name = NameTrio(bootstrap.get_sys_name(), 'routed.3') counter = 0 while not self.publish_three.wait(timeout=3): p.send('3,' + str(counter)) counter += 1
def test_close_does_not_delete_if_anon_but_auto_delete(self): ch = SubscriberChannel() ch._queue_auto_delete = True ch._destroy_queue = Mock() ch._recv_name = NameTrio(sentinel.exchange, 'amq.gen-ABCD') ch.close_impl() self.assertFalse(ch._destroy_queue.called)
def test_close_does_not_delete_if_named(self): ch = SubscriberChannel() ch._queue_auto_delete = False ch._destroy_queue = Mock() ch._recv_name = NameTrio(sentinel.exchange, 'some-named-queue') ch.close_impl() self.assertFalse(ch._destroy_queue.called)
def test_purge(self): transport = Mock() self.ch.on_channel_open(transport) self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue) self.ch._purge() self.ch._transport.purge_impl.assert_called_once_with( queue=sentinel.queue)
def __init__( self, exchange_manager, privileged_transport, node, exchange, exchange_type="topic", durable=False, auto_delete=True, ): XOTransport.__init__( self, exchange_manager=exchange_manager, privileged_transport=privileged_transport, node=node ) NameTrio.__init__(self, exchange=exchange) self._xs_exchange_type = exchange_type self._xs_durable = durable self._xs_auto_delete = auto_delete
def test_purge(self): self.ch._amq_chan = sentinel.amq_chan self.ch._transport = Mock() self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue) self.ch._purge() self.ch._transport.purge_impl.assert_called_once_with( sentinel.amq_chan, queue=sentinel.queue)
def test_send(self): _sendmock = Mock() self.ch._send = _sendmock np = NameTrio('xp', 'key') self.ch.connect(np) self.ch.send('data', {'header': sentinel.headervalue}) _sendmock.assert_called_once_with( np, 'data', headers={'header': sentinel.headervalue})
def test_get_stats(self): self.ch._amq_chan = sentinel.amq_chan self.ch._transport = Mock() self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue) self.ch.get_stats() self.ch._transport.get_stats.assert_called_once_with( sentinel.amq_chan, queue=sentinel.queue)
def __str__(self): return self.xn_type + "-" + NameTrio.__str__(self)
class ListeningBaseEndpoint(BaseEndpoint): """ Establishes channel type for a host of derived, listen/react endpoint factories. """ channel_type = ListenChannel def __init__(self, node=None, name=None, from_name=None, binding=None): BaseEndpoint.__init__(self, node=node) if name: log.warn("ListeningBaseEndpoint: name param is deprecated, please use from_name instead") self._recv_name = from_name or name # ensure NameTrio if not isinstance(self._recv_name, NameTrio): self._recv_name = NameTrio(bootstrap.get_sys_name(), self._recv_name, binding) # if _recv_name is tuple it takes precedence self._ready_event = event.Event() self._binding = binding def _create_channel(self, **kwargs): """ Overrides the BaseEndpoint create channel to supply a transport if our recv name is one. """ if isinstance(self._recv_name, BaseTransport): kwargs.update({'transport':self._recv_name}) return BaseEndpoint._create_channel(self, **kwargs) def get_ready_event(self): """ Returns an async event you can .wait() on. Used to indicate when listen() is ready to start listening. """ return self._ready_event def _setup_listener(self, name, binding=None): self._chan.setup_listener(name, binding=binding) def listen(self, binding=None): log.debug("LEF.listen: binding %s", binding) binding = binding or self._binding or self._recv_name.binding self._ensure_node() kwargs = {} if isinstance(self._recv_name, BaseTransport): kwargs.update({'transport':self._recv_name}) self._chan = self.node.channel(self.channel_type, **kwargs) # @TODO this does not feel right if isinstance(self._recv_name, BaseTransport): self._recv_name.setup_listener(binding, self._setup_listener) self._chan._recv_name = self._recv_name else: self._setup_listener(self._recv_name, binding=binding) self._chan.start_consume() # notify any listeners of our readiness self._ready_event.set() while True: log.debug("LEF: %s blocking, waiting for a message" % str(self._recv_name)) try: newchan = self._chan.accept() msg, headers, delivery_tag = newchan.recv() log.debug("LEF %s received message %s, headers %s, delivery_tag %s", self._recv_name, msg, headers, delivery_tag) log_message(self._recv_name, msg, headers, delivery_tag) except ChannelClosedError as ex: log.debug('Channel was closed during LEF.listen') break try: e = self.create_endpoint(existing_channel=newchan) e._message_received(msg, headers) except Exception: log.exception("Unhandled error while handling received message") raise finally: # ALWAYS ACK newchan.ack(delivery_tag) def close(self): BaseEndpoint.close(self) self._chan.close()
class ListeningBaseEndpoint(BaseEndpoint): """ Establishes channel type for a host of derived, listen/react endpoint factories. """ channel_type = ListenChannel class MessageObject(object): """ Received message wrapper. Contains a body, headers, and a delivery_tag. Internally used by listen, the standard method used by ListeningBaseEndpoint, but will be returned to you if you use get_one_msg or get_n_msgs. If using the latter, you are responsible for calling ack or reject. make_body calls the endpoint's interceptor incoming stack - this may potentially raise an IonException in normal program flow. If this happens, the body/headers attributes will remain None and the error attribute will be set. Calling route() will be a no-op, but ack/reject work. """ def __init__(self, msgtuple, ch, e): self.channel = ch self.endpoint = e self.raw_body, self.raw_headers, self.delivery_tag = msgtuple self.body = None self.headers = None self.error = None def make_body(self): """ Runs received raw message through the endpoint's interceptors. """ try: self.body, self.headers = self.endpoint.intercept_in(self.raw_body, self.raw_headers) except IonException as ex: log.info("MessageObject.make_body raised an error: \n%s", traceback.format_exc(ex)) self.error = ex def ack(self): """ Passthrough to underlying channel's ack. Must call this if using get_one_msg/get_n_msgs. """ self.channel.ack(self.delivery_tag) def reject(self, requeue=False): """ Passthrough to underlying channel's reject. Must call this if using get_one_msg/get_n_msgs. """ self.channel.reject(self.delivery_tag, requeue=requeue) def route(self): """ Call default endpoint's _message_received, where business logic takes place. For instance, a Subscriber would call the registered callback, or an RPCServer would call the Service's operation. You are likely not to use this if using get_one_msg/get_n_msgs. """ if self.error is not None: log.info("Refusing to route a MessageObject with an error") return self.endpoint._message_received(self.body, self.headers) def __init__(self, node=None, name=None, from_name=None, binding=None): BaseEndpoint.__init__(self, node=node) if name: log.warn("ListeningBaseEndpoint: name param is deprecated, please use from_name instead") self._recv_name = from_name or name # ensure NameTrio if not isinstance(self._recv_name, NameTrio): self._recv_name = NameTrio(bootstrap.get_sys_name(), self._recv_name, binding) # if _recv_name is tuple it takes precedence self._ready_event = event.Event() self._binding = binding self._chan = None def _create_channel(self, **kwargs): """ Overrides the BaseEndpoint create channel to supply a transport if our recv name is one. """ if isinstance(self._recv_name, BaseTransport): kwargs.update({'transport':self._recv_name}) return BaseEndpoint._create_channel(self, **kwargs) def get_ready_event(self): """ Returns an async event you can .wait() on. Used to indicate when listen() is ready to start listening. """ return self._ready_event def _setup_listener(self, name, binding=None): self._chan.setup_listener(name, binding=binding) def listen(self, binding=None): """ Main driving method for ListeningBaseEndpoint. Meant to be spawned in a greenlet. This method creates/sets up a channel to listen, starts listening, and consumes messages in a loop until the Endpoint is closed. """ #log.debug("LEF.listen") self.prepare_listener(binding=binding) # notify any listeners of our readiness self._ready_event.set() while True: #log.debug("LEF: %s blocking, waiting for a message", self._recv_name) m = None try: m = self.get_one_msg() m.route() # call default handler except ChannelClosedError as ex: break finally: # ChannelClosedError will go into here too, so make sure we have a message object to ack with if m is not None: m.ack() def prepare_listener(self, binding=None): """ Creates a channel, prepares it, and begins consuming on it. Used by listen. """ #log.debug("LEF.prepare_listener: binding %s", binding) self.initialize(binding=binding) self.activate() def initialize(self, binding=None): """ Creates a channel and prepares it for use. After this, the endpoint is inthe ready state. """ binding = binding or self._binding or self._recv_name.binding self._ensure_node() kwargs = {} if isinstance(self._recv_name, BaseTransport): kwargs.update({'transport':self._recv_name}) self._chan = self.node.channel(self.channel_type, **kwargs) # @TODO this does not feel right if isinstance(self._recv_name, BaseTransport): self._recv_name.setup_listener(binding, self._setup_listener) self._chan._recv_name = self._recv_name else: self._setup_listener(self._recv_name, binding=binding) def activate(self): """ Begins consuming. You must have called initialize first. """ assert self._chan self._chan.start_consume() def deactivate(self): """ Stops consuming. You must have called initialize and activate first. """ assert self._chan self._chan.stop_consume() # channel will yell at you if this is invalid def get_stats(self): """ Returns a tuple of the form (# ready messages, # of consumers). This endpoint must have been initialized in order to have a valid queue to work on. Passes down to the channel layer to get this info. """ assert self._chan return self._chan.get_stats() def _get_n_msgs(self, num=1, timeout=None): """ Internal method to accept n messages, create MessageObject wrappers, return them. INBOUND INTERCEPTORS ARE PROCESSED HERE. If the Interceptor stack throws an IonException, the response will be sent immediatly and the MessageObject returned to you will not have body/headers set and will have error set. You should expect to check body/headers or error. """ assert self._chan, "_get_n_msgs: needs the endpoint to have been initialized" mos = [] newch = self._chan.accept(n=num, timeout=timeout) for x in xrange(newch._recv_queue.qsize()): mo = self.MessageObject(newch.recv(), newch, self.create_endpoint(existing_channel=newch)) mo.make_body() # puts through EP interceptors mos.append(mo) log_message("MESSAGE RECV >>> RPC-request", mo.raw_body, mo.raw_headers, self._recv_name, mo.delivery_tag, is_send=False) return mos def get_one_msg(self, timeout=None): """ Receives one message. Blocks until one message is received, or the optional timeout is reached. INBOUND INTERCEPTORS ARE PROCESSED HERE. If the Interceptor stack throws an IonException, the response will be sent immediatly and the MessageObject returned to you will not have body/headers set and will have error set. You should expect to check body/headers or error. @raises ChannelClosedError If the channel has been closed. @raises Timeout If no messages available when timeout is reached. @returns A MessageObject. """ mos = self._get_n_msgs(num=1, timeout=timeout) return mos[0] def get_n_msgs(self, num, timeout=None): """ Receives num messages. INBOUND INTERCEPTORS ARE PROCESSED HERE. If the Interceptor stack throws an IonException, the response will be sent immediatly and the MessageObject returned to you will not have body/headers set and will have error set. You should expect to check body/headers or error. Blocks until all messages received, or the optional timeout is reached. @raises ChannelClosedError If the channel has been closed. @raises Timeout If no messages available when timeout is reached. @returns A list of MessageObjects. """ return self._get_n_msgs(num, timeout=timeout) def get_all_msgs(self, timeout=None): """ Receives all available messages on the queue. WARNING: If the queue is not exclusive, there is a possibility this method behaves incorrectly. You should always pass a timeout to this method. Blocks until all messages received, or the optional timeout is reached. @raises ChannelClosedError If the channel has been closed. @raises Timeout If no messages available when timeout is reached. @returns A list of MessageObjects. """ n, _ = self.get_stats() return self._get_n_msgs(n, timeout=timeout) def close(self): BaseEndpoint.close(self) self._chan.close() def get_stats(self): """ Passthrough to channel's get_stats. """ if not self._chan: raise EndpointError("No channel attached") return self._chan.get_stats()