def test_kill_closes_connections(rabbit_manager, rabbit_config): container = Mock() container.config = rabbit_config container.max_workers = 1 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) class Handler(object): queue = ham_queue def handle_message(self, body, message): pass queue_consumer.register_provider(Handler()) queue_consumer.start() # kill should close all connections queue_consumer.kill() # no connections should remain for our vhost vhost = rabbit_config['vhost'] connections = get_rabbit_connections(vhost, rabbit_manager) if connections: for connection in connections: assert connection['vhost'] != vhost
def test_unserialisable_headers(rabbit_manager, rabbit_config): vhost = rabbit_config["vhost"] container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = rabbit_config container.spawn_managed_thread = eventlet.spawn ctx_data = {"language": "en", "customheader": None} service = Mock() worker_ctx = CustomWorkerContext(container, service, DummyProvider("method"), data=ctx_data) publisher = Publisher(exchange=foobar_ex, queue=foobar_queue).bind(container, "publish") publisher.setup() publisher.start() service.publish = publisher.get_dependency(worker_ctx) service.publish("msg") messages = rabbit_manager.get_messages(vhost, foobar_queue.name) assert messages[0]["properties"]["headers"] == { "nameko.language": "en", "nameko.call_id_stack": ["service.method.0"], # no `customheader` }
def test_unserialisable_headers(rabbit_manager, rabbit_config): vhost = rabbit_config['vhost'] container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = rabbit_config container.spawn_managed_thread = eventlet.spawn ctx_data = {'language': 'en', 'customheader': None} service = Mock() worker_ctx = CustomWorkerContext( container, service, 'method', data=ctx_data) publisher = PublishProvider(exchange=foobar_ex, queue=foobar_queue) publisher.bind("publish", container) publisher.prepare() publisher.start() publisher.inject(worker_ctx) service.publish("msg") messages = rabbit_manager.get_messages(vhost, foobar_queue.name) assert messages[0]['properties']['headers'] == { 'nameko.language': 'en', 'nameko.call_id_stack': ['service.method.0'], # no `customheader` }
def test_reconnect_on_socket_error(): container = Mock() container.config = {AMQP_URI_CONFIG_KEY: None} container.max_workers = 1 container.spawn_managed_thread = spawn_thread connection_revived = Mock() queue_consumer = QueueConsumer() queue_consumer.on_connection_revived = connection_revived queue_consumer.bind("queue_consumer", container) handler = MessageHandler() queue_consumer.register_provider(handler) queue_consumer.start() with patch.object( Connection, 'drain_events', autospec=True) as drain_events: drain_events.side_effect = socket.error('test-error') def check_reconnected(): assert connection_revived.call_count > 1 assert_stops_raising(check_reconnected)
def test_reconnect_on_socket_error(rabbit_config): container = Mock(spec=ServiceContainer) container.shared_extensions = {} container.config = rabbit_config container.max_workers = 1 container.spawn_managed_thread = spawn_thread connection_revived = Mock() queue_consumer = QueueConsumer().bind(container) queue_consumer.setup() queue_consumer.on_connection_revived = connection_revived handler = MessageHandler() queue_consumer.register_provider(handler) queue_consumer.start() with patch.object( Connection, 'drain_events', autospec=True) as drain_events: drain_events.side_effect = socket.error('test-error') def check_reconnected(): assert connection_revived.call_count > 1 assert_stops_raising(check_reconnected) queue_consumer.unregister_provider(handler) queue_consumer.stop()
def test_reconnect_on_socket_error(rabbit_config): container = Mock() container.config = rabbit_config container.max_workers = 1 container.spawn_managed_thread = spawn_thread connection_revived = Mock() queue_consumer = QueueConsumer() queue_consumer.on_connection_revived = connection_revived queue_consumer.bind("queue_consumer", container) handler = MessageHandler() queue_consumer.register_provider(handler) queue_consumer.start() with patch.object(Connection, 'drain_events', autospec=True) as drain_events: drain_events.side_effect = socket.error('test-error') def check_reconnected(): assert connection_revived.call_count > 1 assert_stops_raising(check_reconnected) queue_consumer.unregister_provider(handler) queue_consumer.stop()
def test_unserialisable_headers(rabbit_manager, rabbit_config): vhost = rabbit_config['vhost'] container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = rabbit_config container.spawn_managed_thread = eventlet.spawn ctx_data = {'language': 'en', 'customheader': None} service = Mock() worker_ctx = CustomWorkerContext(container, service, DummyProvider('method'), data=ctx_data) publisher = PublishProvider(exchange=foobar_ex, queue=foobar_queue) publisher.bind("publish", container) publisher.prepare() publisher.start() publisher.inject(worker_ctx) service.publish("msg") messages = rabbit_manager.get_messages(vhost, foobar_queue.name) assert messages[0]['properties']['headers'] == { 'nameko.language': 'en', 'nameko.call_id_stack': ['service.method.0'], # no `customheader` }
def test_consume_from_rabbit(rabbit_manager, rabbit_config): vhost = rabbit_config['vhost'] container = Mock(spec=ServiceContainer) container.worker_ctx_cls = CustomWorkerContext container.service_name = "service" container.config = rabbit_config container.max_workers = 10 def spawn_thread(method, protected): return eventlet.spawn(method) container.spawn_managed_thread = spawn_thread worker_ctx = CustomWorkerContext(container, None, None) factory = DependencyFactory( ConsumeProvider, queue=foobar_queue, requeue_on_error=False) consumer = factory.create_and_bind_instance("injection_name", container) # prepare and start dependencies consumer.prepare() consumer.queue_consumer.prepare() consumer.start() consumer.queue_consumer.start() # test queue, exchange and binding created in rabbit exchanges = rabbit_manager.get_exchanges(vhost) queues = rabbit_manager.get_queues(vhost) bindings = rabbit_manager.get_queue_bindings(vhost, foobar_queue.name) assert "foobar_ex" in [exchange['name'] for exchange in exchanges] assert "foobar_queue" in [queue['name'] for queue in queues] assert "foobar_ex" in [binding['source'] for binding in bindings] # test message consumed from queue container.spawn_worker.return_value = worker_ctx headers = {'nameko.language': 'en', 'nameko.customheader': 'customvalue'} rabbit_manager.publish( vhost, foobar_ex.name, '', 'msg', properties=dict(headers=headers)) ctx_data = { 'language': 'en', 'customheader': 'customvalue', } with wait_for_call(CONSUME_TIMEOUT, container.spawn_worker) as method: method.assert_called_once_with( consumer, ('msg', ), {}, context_data=ctx_data, handle_result=ANY_PARTIAL) handle_result = method.call_args[1]['handle_result'] # ack message handle_result(worker_ctx, 'result') # stop will hang if the consumer hasn't acked or requeued messages with eventlet.timeout.Timeout(CONSUME_TIMEOUT): consumer.stop()
def test_consume_from_rabbit(container_factory, rabbit_manager, rabbit_config): vhost = rabbit_config["vhost"] container = Mock(spec=ServiceContainer) container.shared_extensions = {} container.worker_ctx_cls = CustomWorkerContext container.service_name = "service" container.config = rabbit_config container.max_workers = 10 def spawn_thread(method, protected): return eventlet.spawn(method) container.spawn_managed_thread = spawn_thread worker_ctx = CustomWorkerContext(container, None, DummyProvider()) consumer = Consumer(queue=foobar_queue, requeue_on_error=False).bind(container, "publish") # prepare and start extensions consumer.setup() consumer.queue_consumer.setup() consumer.start() consumer.queue_consumer.start() # test queue, exchange and binding created in rabbit exchanges = rabbit_manager.get_exchanges(vhost) queues = rabbit_manager.get_queues(vhost) bindings = rabbit_manager.get_queue_bindings(vhost, foobar_queue.name) assert "foobar_ex" in [exchange["name"] for exchange in exchanges] assert "foobar_queue" in [queue["name"] for queue in queues] assert "foobar_ex" in [binding["source"] for binding in bindings] # test message consumed from queue container.spawn_worker.return_value = worker_ctx headers = {"nameko.language": "en", "nameko.customheader": "customvalue"} rabbit_manager.publish(vhost, foobar_ex.name, "", "msg", properties=dict(headers=headers)) ctx_data = {"language": "en", "customheader": "customvalue"} with wait_for_call(CONSUME_TIMEOUT, container.spawn_worker) as method: method.assert_called_once_with(consumer, ("msg",), {}, context_data=ctx_data, handle_result=ANY_PARTIAL) handle_result = method.call_args[1]["handle_result"] # ack message handle_result(worker_ctx, "result") # stop will hang if the consumer hasn't acked or requeued messages with eventlet.timeout.Timeout(CONSUME_TIMEOUT): consumer.stop() consumer.queue_consumer.kill()
def test_provider_uses_config_for_interval(): container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = {'spam-conf': 10} container.spawn_managed_thread = eventlet.spawn timer = TimerProvider(interval=None, config_key='spam-conf') timer.bind('foobar', container) timer.prepare() assert timer.interval == 10
def test_reentrant_start_stops(rabbit_config): container = Mock() container.config = rabbit_config container.max_workers = 3 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) queue_consumer.start() gt = queue_consumer._gt # nothing should happen as the consumer has already been started queue_consumer.start() assert gt is queue_consumer._gt
def test_kill_stops_timer(): container = Mock(spec=ServiceContainer) container.service_name = "service" container.spawn_managed_thread = eventlet.spawn timer = Timer(interval=0).bind(container, "method") timer.setup() timer.start() with wait_for_call(1, container.spawn_worker): timer.kill() # unless the timer is dead, the following nap would cause a timer # to trigger eventlet.sleep(0.1) assert container.spawn_worker.call_count == 1
def test_reentrant_start_stops(rabbit_config): container = Mock() container.config = rabbit_config container.max_workers = 3 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) queue_consumer.start() gt = queue_consumer._gt # nothing should happen as the consumer has already been started queue_consumer.start() assert gt is queue_consumer._gt queue_consumer.kill()
def test_kill_stops_timer(): container = Mock(spec=ServiceContainer) container.service_name = "service" container.spawn_managed_thread = eventlet.spawn timer = TimerProvider(interval=0, config_key=None) timer.bind('foobar', container) timer.prepare() timer.start() with wait_for_call(1, container.spawn_worker): timer.kill() # unless the timer is dead, the following nap would cause a timer # to trigger eventlet.sleep(0.1) assert container.spawn_worker.call_count == 1
def test_stop_while_starting(rabbit_config): started = Event() container = Mock(spec=ServiceContainer) container.shared_extensions = {} container.config = rabbit_config container.max_workers = 3 container.spawn_managed_thread = spawn_thread class BrokenConnConsumer(QueueConsumer): def consume(self, *args, **kwargs): started.send(None) # kombu will retry again and again on broken connections # so we have to make sure the event is reset to allow consume # to be called again started.reset() return super(BrokenConnConsumer, self).consume(*args, **kwargs) queue_consumer = BrokenConnConsumer().bind(container) queue_consumer.setup() handler = MessageHandler() queue_consumer.register_provider(handler) with eventlet.Timeout(TIMEOUT): with patch.object(Connection, 'connect', autospec=True) as connect: # patch connection to raise an error connect.side_effect = TimeoutError('test') # try to start the queue consumer gt = eventlet.spawn(queue_consumer.start) # wait for the queue consumer to begin starting and # then immediately stop it started.wait() with eventlet.Timeout(TIMEOUT): queue_consumer.unregister_provider(handler) queue_consumer.stop() with eventlet.Timeout(TIMEOUT): # we expect the queue_consumer.start thread to finish # almost immediately adn when it does the queue_consumer thread # should be dead too while not gt.dead: eventlet.sleep() assert queue_consumer._gt.dead
def test_kill_stops_timer(): container = Mock(spec=ServiceContainer) container.service_name = "service" container.spawn_managed_thread = eventlet.spawn timer = TimerProvider(interval=0, config_key=None) timer.bind('foobar', container) timer.prepare() timer.start() with wait_for_call(1, container.spawn_worker): timer.kill(Exception('time')) # unless the timer is dead, the following nap would cause a timer # to trigger eventlet.sleep(0.1) assert container.spawn_worker.call_count == 1
def test_reentrant_start_stops(): container = Mock() container.config = {AMQP_URI_CONFIG_KEY: 'memory://'} container.max_workers = 3 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) queue_consumer.start() gt = queue_consumer._gt # nothing should happen as the consumer has already been started queue_consumer.start() assert gt is queue_consumer._gt queue_consumer.kill()
def test_publish_to_rabbit(rabbit_manager, rabbit_config): vhost = rabbit_config['vhost'] container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = rabbit_config container.spawn_managed_thread = eventlet.spawn ctx_data = {'language': 'en', 'customheader': 'customvalue'} service = Mock() worker_ctx = CustomWorkerContext(container, service, DummyProvider('method'), data=ctx_data) publisher = PublishProvider(exchange=foobar_ex, queue=foobar_queue) publisher.bind("publish", container) # test queue, exchange and binding created in rabbit publisher.prepare() publisher.start() exchanges = rabbit_manager.get_exchanges(vhost) queues = rabbit_manager.get_queues(vhost) bindings = rabbit_manager.get_queue_bindings(vhost, foobar_queue.name) assert "foobar_ex" in [exchange['name'] for exchange in exchanges] assert "foobar_queue" in [queue['name'] for queue in queues] assert "foobar_ex" in [binding['source'] for binding in bindings] # test message published to queue publisher.inject(worker_ctx) service.publish("msg") messages = rabbit_manager.get_messages(vhost, foobar_queue.name) assert ['msg'] == [msg['payload'] for msg in messages] # test message headers assert messages[0]['properties']['headers'] == { 'nameko.language': 'en', 'nameko.customheader': 'customvalue', 'nameko.call_id_stack': ['service.method.0'], }
def test_on_consume_error_kills_consumer(): container = Mock(spec=ServiceContainer) container.shared_extensions = {} container.config = {AMQP_URI_CONFIG_KEY: 'memory://'} container.max_workers = 1 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer().bind(container) queue_consumer.setup() handler = MessageHandler() queue_consumer.register_provider(handler) with patch.object(queue_consumer, 'on_consume_ready') as on_consume_ready: on_consume_ready.side_effect = Exception('err') queue_consumer.start() with pytest.raises(Exception): queue_consumer._gt.wait()
def test_on_consume_error_kills_consumer(): container = Mock() container.config = {AMQP_URI_CONFIG_KEY: None} container.max_workers = 1 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) handler = MessageHandler() queue_consumer.register_provider(handler) with patch.object(queue_consumer, 'on_consume_ready') as on_consume_ready: on_consume_ready.side_effect = Exception('err') queue_consumer.start() with pytest.raises(Exception): queue_consumer._gt.wait()
def test_provider(): container = Mock(spec=ServiceContainer) container.service_name = "service" container.spawn_managed_thread = eventlet.spawn timer = Timer(interval=0.1).bind(container, "method") timer.setup() timer.start() assert timer.interval == 0.1 with wait_for_call(1, container.spawn_worker) as spawn_worker: with Timeout(1): timer.stop() # the timer should have stopped and should only have spawned # a single worker spawn_worker.assert_called_once_with(timer, (), {}) assert timer.gt.dead
def test_on_consume_error_kills_consumer(): container = Mock() container.config = {AMQP_URI_CONFIG_KEY: 'memory://'} container.max_workers = 1 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) handler = MessageHandler() queue_consumer.register_provider(handler) with patch.object(queue_consumer, 'on_consume_ready') as on_consume_ready: on_consume_ready.side_effect = Exception('err') queue_consumer.start() with pytest.raises(Exception): queue_consumer._gt.wait()
def test_publish_to_rabbit(rabbit_manager, rabbit_config): vhost = rabbit_config['vhost'] container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = rabbit_config container.spawn_managed_thread = eventlet.spawn ctx_data = {'language': 'en', 'customheader': 'customvalue'} service = Mock() worker_ctx = CustomWorkerContext( container, service, 'method', data=ctx_data) publisher = PublishProvider(exchange=foobar_ex, queue=foobar_queue) publisher.bind("publish", container) # test queue, exchange and binding created in rabbit publisher.prepare() publisher.start() exchanges = rabbit_manager.get_exchanges(vhost) queues = rabbit_manager.get_queues(vhost) bindings = rabbit_manager.get_queue_bindings(vhost, foobar_queue.name) assert "foobar_ex" in [exchange['name'] for exchange in exchanges] assert "foobar_queue" in [queue['name'] for queue in queues] assert "foobar_ex" in [binding['source'] for binding in bindings] # test message published to queue publisher.inject(worker_ctx) service.publish("msg") messages = rabbit_manager.get_messages(vhost, foobar_queue.name) assert ['msg'] == [msg['payload'] for msg in messages] # test message headers assert messages[0]['properties']['headers'] == { 'nameko.language': 'en', 'nameko.customheader': 'customvalue', 'nameko.call_id_stack': ['service.method.0'], }
def test_error_stops_consumer_thread(): container = Mock() container.config = {AMQP_URI_CONFIG_KEY: None} container.max_workers = 3 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) handler = MessageHandler() queue_consumer.register_provider(handler) with eventlet.Timeout(TIMEOUT): with patch.object( Connection, 'drain_events', autospec=True) as drain_events: drain_events.side_effect = Exception('test') queue_consumer.start() with pytest.raises(Exception) as exc_info: queue_consumer._gt.wait() assert exc_info.value.args == ('test',)
def test_publish_to_rabbit(rabbit_manager, rabbit_config): vhost = rabbit_config["vhost"] container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = rabbit_config container.spawn_managed_thread = eventlet.spawn ctx_data = {"language": "en", "customheader": "customvalue"} service = Mock() worker_ctx = CustomWorkerContext(container, service, DummyProvider("method"), data=ctx_data) publisher = Publisher(exchange=foobar_ex, queue=foobar_queue).bind(container, "publish") # test queue, exchange and binding created in rabbit publisher.setup() publisher.start() exchanges = rabbit_manager.get_exchanges(vhost) queues = rabbit_manager.get_queues(vhost) bindings = rabbit_manager.get_queue_bindings(vhost, foobar_queue.name) assert "foobar_ex" in [exchange["name"] for exchange in exchanges] assert "foobar_queue" in [queue["name"] for queue in queues] assert "foobar_ex" in [binding["source"] for binding in bindings] # test message published to queue service.publish = publisher.get_dependency(worker_ctx) service.publish("msg") messages = rabbit_manager.get_messages(vhost, foobar_queue.name) assert ["msg"] == [msg["payload"] for msg in messages] # test message headers assert messages[0]["properties"]["headers"] == { "nameko.language": "en", "nameko.customheader": "customvalue", "nameko.call_id_stack": ["service.method.0"], }
def test_error_stops_consumer_thread(): container = Mock() container.config = {AMQP_URI_CONFIG_KEY: 'memory://'} container.max_workers = 3 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) handler = MessageHandler() queue_consumer.register_provider(handler) with eventlet.Timeout(TIMEOUT): with patch.object(Connection, 'drain_events', autospec=True) as drain_events: drain_events.side_effect = Exception('test') queue_consumer.start() with pytest.raises(Exception) as exc_info: queue_consumer._gt.wait() assert exc_info.value.args == ('test', )
def test_provider(): container = Mock(spec=ServiceContainer) container.service_name = "service" container.config = Mock() container.spawn_managed_thread = eventlet.spawn timer = TimerProvider(interval=0, config_key=None) timer.bind('foobar', container) timer.prepare() assert timer.interval == 0 timer.start() with wait_for_call(1, container.spawn_worker) as spawn_worker: with Timeout(1): timer.stop() # the timer should have stopped and should only have spawned # a single worker spawn_worker.assert_called_once_with(timer, (), {}) assert timer.gt.dead
def test_kill_closes_connections(rabbit_manager, rabbit_config): container = Mock() container.config = rabbit_config container.max_workers = 1 container.spawn_managed_thread = spawn_thread queue_consumer = QueueConsumer() queue_consumer.bind("queue_consumer", container) class Handler(object): queue = ham_queue def handle_message(self, body, message): pass queue_consumer.register_provider(Handler()) queue_consumer.start() # kill should close all connections queue_consumer.kill(Exception('test-kill')) connections = rabbit_manager.get_connections() assert connections is None
def test_consume_from_rabbit(rabbit_manager, rabbit_config): vhost = rabbit_config['vhost'] container = Mock(spec=ServiceContainer) container.worker_ctx_cls = CustomWorkerContext container.service_name = "service" container.config = rabbit_config container.max_workers = 10 def spawn_thread(method, protected): return eventlet.spawn(method) container.spawn_managed_thread = spawn_thread worker_ctx = CustomWorkerContext(container, None, DummyProvider()) factory = DependencyFactory(ConsumeProvider, queue=foobar_queue, requeue_on_error=False) consumer = factory.create_and_bind_instance("injection_name", container) # prepare and start dependencies consumer.prepare() consumer.queue_consumer.prepare() consumer.start() consumer.queue_consumer.start() # test queue, exchange and binding created in rabbit exchanges = rabbit_manager.get_exchanges(vhost) queues = rabbit_manager.get_queues(vhost) bindings = rabbit_manager.get_queue_bindings(vhost, foobar_queue.name) assert "foobar_ex" in [exchange['name'] for exchange in exchanges] assert "foobar_queue" in [queue['name'] for queue in queues] assert "foobar_ex" in [binding['source'] for binding in bindings] # test message consumed from queue container.spawn_worker.return_value = worker_ctx headers = {'nameko.language': 'en', 'nameko.customheader': 'customvalue'} rabbit_manager.publish(vhost, foobar_ex.name, '', 'msg', properties=dict(headers=headers)) ctx_data = { 'language': 'en', 'customheader': 'customvalue', } with wait_for_call(CONSUME_TIMEOUT, container.spawn_worker) as method: method.assert_called_once_with(consumer, ('msg', ), {}, context_data=ctx_data, handle_result=ANY_PARTIAL) handle_result = method.call_args[1]['handle_result'] # ack message handle_result(worker_ctx, 'result') # stop will hang if the consumer hasn't acked or requeued messages with eventlet.timeout.Timeout(CONSUME_TIMEOUT): consumer.stop() consumer.queue_consumer.kill()
def test_prefetch_count(rabbit_manager, rabbit_config): container = Mock() container.config = rabbit_config container.max_workers = 1 container.spawn_managed_thread = spawn_thread queue_consumer1 = QueueConsumer() queue_consumer1.bind("queue_consumer", container) queue_consumer2 = QueueConsumer() queue_consumer2.bind("queue_consumer", container) consumer_continue = Event() class Handler1(object): queue = ham_queue def handle_message(self, body, message): consumer_continue.wait() queue_consumer1.ack_message(message) messages = [] class Handler2(object): queue = ham_queue def handle_message(self, body, message): messages.append(body) queue_consumer2.ack_message(message) handler1 = Handler1() handler2 = Handler2() queue_consumer1.register_provider(handler1) queue_consumer2.register_provider(handler2) queue_consumer1.start() queue_consumer2.start() vhost = rabbit_config['vhost'] # the first consumer only has a prefetch_count of 1 and will only # consume 1 message and wait in handler1() rabbit_manager.publish(vhost, 'spam', '', 'ham') # the next message will go to handler2() no matter of any prefetch_count rabbit_manager.publish(vhost, 'spam', '', 'eggs') # the third message is only going to handler2 because the first consumer # has a prefetch_count of 1 and thus is unable to deal with another message # until having ACKed the first one rabbit_manager.publish(vhost, 'spam', '', 'bacon') with eventlet.Timeout(TIMEOUT): while len(messages) < 2: eventlet.sleep() # allow the waiting consumer to ack its message consumer_continue.send(None) assert messages == ['eggs', 'bacon'] queue_consumer1.unregister_provider(handler1) queue_consumer2.unregister_provider(handler2) queue_consumer1.kill() queue_consumer2.kill()