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_nested_dependencies(rabbit_config): container = Mock() container.config = rabbit_config bar_factory = DependencyFactory(BarProvider) bar = bar_factory.create_and_bind_instance("bar", container) dependencies = list(bar.nested_dependencies) assert len(dependencies) == 2 assert dependencies[0].container == dependencies[1].container == container assert set([type(dep) for dep in dependencies]) == set([SharedProvider, NestedProvider])
def consume(queue, requeue_on_error=False): """ Decorates a method as a message consumer. Messages from the queue will be deserialized depending on their content type and passed to the the decorated method. When the consumer method returns without raising any exceptions, the message will automatically be acknowledged. If any exceptions are raised during the consumption and `requeue_on_error` is True, the message will be requeued. Example:: @consume(...) def handle_message(self, body): if not self.spam(body): raise Exception('message will be requeued') self.shrub(body) Args: queue: The queue to consume from. """ return DependencyFactory(ConsumeProvider, queue, requeue_on_error)
def rpc(expected_exceptions=()): """ Mark a method to be exposed over rpc :Parameters: expected_exceptions : exception class or tuple of exception classes Stashed on the provider instance for later inspection by other dependencies in the worker lifecycle. Use for exceptions caused by the caller (e.g. bad arguments). """ return DependencyFactory(RpcProvider, expected_exceptions)
def file_logger(path=None): """ User docs for file logger """ if path is not None: check_path = path if not os.path.exists(check_path): check_path = os.path.dirname(path) if not os.access(check_path, os.W_OK): raise InvalidPath("File or dir not writable: {}".format(path)) return DependencyFactory(LogFile, path)
def timer(interval=None, config_key=None): ''' Decorates a method as a timer, which will be called every `interval` sec. Either the `interval` or the `config_key` have to be provided or both. If the `config_key` is given the value for that key in the config will be used as the interval otherwise the `interval` provided will be used. Example:: class Foobar(object): @timer(interval=5, config_key='foobar_interval') def handle_timer(self): self.shrub(body) ''' return DependencyFactory(TimerProvider, interval, config_key)
def injection_provider(): return DependencyFactory(ExampleProvider)
def shopping_basket(): """ A shopping basket tied to the current user. """ return DependencyFactory(ShoppingBasket)
def custom_value(): return DependencyFactory(ContextDataProvider, CUSTOM_CONTEXT_KEY)
def stdout(): return DependencyFactory(StdoutProvider)
def foobar(*args, **kwargs): """foobar-doc""" return DependencyFactory(FooProvider, *args, **kwargs)
def foobar(): return DependencyFactory(CallCollectingEntrypointProvider)
def auth_token(): return DependencyFactory(ContextDataProvider, AUTH_TOKEN_CONTEXT_KEY)
def context_reader(): return DependencyFactory(ContextReader)
def user_id(): return DependencyFactory(ContextDataProvider, USER_ID_CONTEXT_KEY)
def user_agent(): return DependencyFactory(ContextDataProvider, USER_AGENT_CONTEXT_KEY)
def language(): return DependencyFactory(ContextDataProvider, LANGUAGE_CONTEXT_KEY)
def rpc(): return DependencyFactory(NovaRpcProvider)
def nova_rpc_consumer(): return DependencyFactory(NovaRpcConsumer)
def shared_provider(*args, **kwargs): return DependencyFactory(SharedProvider, *args, **kwargs)
def translator(): return DependencyFactory(Translator)
def nested_provider(*args, **kwargs): return DependencyFactory(NestedProvider, *args, **kwargs)
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 barfoo(*args, **kwargs): return DependencyFactory(BarProvider, *args, **kwargs)
def event_dispatcher(): return DependencyFactory(EventDispatcher)
def call_collector(): return DependencyFactory(CallCollectingInjectionProvider)
def event_handler(service_name, event_type, handler_type=SERVICE_POOL, reliable_delivery=True, requeue_on_error=False, event_handler_cls=EventHandler): r""" Decorate a method as a handler of ``event_type`` events on the service called ``service_name``. ``event_type`` must be either a subclass of :class:`~.Event` with a class attribute ``type`` or a string matching the value of this attribute. ``handler_type`` determines the behaviour of the handler: - ``events.SERVICE_POOL``: Event handlers will be pooled by service type and handler-method and one from each pool will receive the event. :: .-[queue]- (service X handler-method-1) / exchange o --[queue]- (service X handler-method-2) \ \ (service Y(instance 1) hanlder-method) \ / [queue] \ (service Y(instance 2) handler-method) - ``events.SINGLETON``: Events will be received by only one registered handler. If requeued on error, they may be given to a different handler. :: (service X handler-method) / exchange o -- [queue] \ (service Y handler-method) - ``events.BROADCAST``: Events will be received by every handler. This will broadcast to every service instance, not just every service type - use wisely! :: [queue]- (service X(instance 1) handler-method) / exchange o - [queue]- (service X(instance 2) handler-method) \ [queue]- (service Y handler-method) If ``requeue_on_error``, handlers will return the event to the queue if an error occurs while handling it. Defaults to False. If ``reliable_delivery``, events will be kept in the queue until there is a handler to consume them. Defaults to ``True``. ``event_handler_cls`` may be specified to use a different EventHandler (sub)class for custom behaviour. Raises an ``EventHandlerConfigurationError`` if the ``handler_type`` is set to ``BROADCAST`` and ``reliable_delivery`` is set to ``True``. """ if reliable_delivery and handler_type is BROADCAST: raise EventHandlerConfigurationError( "Broadcast event handlers cannot be configured with reliable " "delivery.") if isinstance(event_type, type) and issubclass(event_type, Event): event_type = event_type.type elif not isinstance(event_type, basestring): raise TypeError( 'event_type must be either a nameko.events.Event subclass or a ' 'string a string matching the Event.type value. ' 'Got {}'.format(type(event_type).__name__)) return DependencyFactory(event_handler_cls, service_name, event_type, handler_type, reliable_delivery, requeue_on_error)
def dummy(): return DependencyFactory(DummyEntrypoint)
def once(*args, **kwargs): """ Fire the decorated entrypoint once, immediately. """ return DependencyFactory(OnceProvider, args, kwargs)
def worker_logger(): return DependencyFactory(WorkerErrorLogger)
def stdin(): """ Receive messages from `sys.stdin` """ return DependencyFactory(StdinProvider)