Esempio n. 1
0
    def _call_service_method(self, info, args, kwargs):
        """
        Calls method and returns the tuple with `Exception` instance
        or `None` and result or `None`.
        `info` can be tuple containing service name & method name
        or the actual callable method.
        """
        try:
            if isinstance(info, tuple):
                service_name, fn_name = info
                fn = self._get_method(service_name, fn_name)
            else:
                fn_name = info.__name__
                fn = info
            self._fire_hook('pre_call', fn_name, args, kwargs)
            result = (None, fn(*args, **kwargs))

            args_str = ', '.join(map(repr, args))
            kwargs_str = ', '.join(
                ['{}={}'.format(k, repr(v)) for k, v in kwargs.items()])

            args_kwargs_str = ', '.join((args_str, kwargs_str))

            log.debug('{}({})'.format(fn_name, args_kwargs_str))
            self._fire_hook('post_success', fn_name, args, kwargs, result)
            return result
        except Exception as e:
            self._log_method_error(fn_name, e)
            self._fire_hook('post_error', fn_name, args, kwargs, e)
            return (str(e), None)
Esempio n. 2
0
    def _create_fanout_exchange(self, Consumer, channel):
        """
        Creates a fanout queue to accept notifications.
        """
        exchange_name = '{}_fanout'.format(self.exchange)
        log.debug('Declaring fanout exchange %s', exchange_name)
        exchange = kombu.Exchange(name=exchange_name,
                                  channel=channel,
                                  durable=False,
                                  type='fanout')
        exchange.declare()
        queue_name = 'fanout_callback_{}'.format(uuid.uuid4())
        log.debug('Declaring fanout queue %s', queue_name)
        queue = kombu.Queue(name=queue_name,
                            exchange=exchange,
                            exclusive=True,
                            durable=False,
                            channel=channel)
        queue.declare()
        consumer = Consumer(
            # self.connection,
            queues=[queue],
            on_message=self._on_broadcast,
            no_ack=True
            # no_ack=True
        )

        return consumer
Esempio n. 3
0
 def _create_service_queues(self, services, Consumer, channel):
     """
     Creates necessary AMQP queues, one per service.
     """
     log.debug('Declaring exchange %s', self.exchange)
     exchange = kombu.Exchange(self.exchange,
                               channel=channel,
                               durable=False)
     exchange.declare()
     queues = []
     for service in services.values():
         queue_name = '{}_service_{}'.format(self.exchange, service.name)
         log.debug('Declaring service queue %s', queue_name)
         queue = kombu.Queue(
             channel=channel,
             name=queue_name,
             exchange=exchange,
             routing_key=queue_name,
             exclusive=False,
             durable=False,
         )
         queue.declare()
         queues.append(queue)
     consumer = Consumer(queues=queues,
                         on_message=self._on_message,
                         no_ack=False)
     return consumer
Esempio n. 4
0
 def _run_scheduled_with_local_timer(self, fn, timeout):
     """
     Runs the method and reschedules it to be executed again.
     """
     fn_name = fn.__name__
     exception, _ = self._call_service_method(fn, (), {})
     if not exception:
         log.debug('Scheduled function %s completed successfully.', fn_name)
     self._schedule_with_local_timer(fn, timeout)
Esempio n. 5
0
    def _validate_message(self, message):
        """
        Checks and acknowledges a received message if it can be handled
        by any registered service.
        """
        try:
            service_name = message.delivery_info['routing_key'][
                self.queue_name_offset:]

            if service_name not in self.services:  # pragma: no cover
                return

            message.ack()

            try:
                log.debug('Got invocation ..{}'.format(
                    str(message.properties['correlation_id'])[-4:]))
                requested_codec, (fn_name, args,
                                  kwargs) = self._decode_message(message)
            except Exception as e:
                log.error(str(e))
            else:
                result = self._call_service_method((service_name, fn_name),
                                                   args, kwargs)

                log.debug('Publishing response for invocation ..{}'.format(
                    str(message.properties['correlation_id'])[-4:]))

                # Node.channel_lock.acquire()
                try:
                    with producers[self.connection].acquire(
                            block=True) as producer:
                        producer.publish(
                            requested_codec.encode(result),
                            exchange=self.exchange,
                            routing_key=message.properties['reply_to'],
                            correlation_id=message.properties['correlation_id']
                            # body=requested_codec.encode(result)
                        )
                except Exception as e:
                    log.error('Failed to publish message')
                    traceback.print_exc()
                # Node.channel_lock.release()
        except Exception as e:
            log.error('Unhandled exception in _validate_message.')
            traceback.print_exc()
Esempio n. 6
0
    def _on_broadcast(self, message):
        """
        Called when a notification is received.
        Does not acknowledge notifications because they're
        delivered via `fanout` exchange.
        """
        try:
            try:
                requested_codec, (event, data) = self._decode_message(message)
            except Exception as e:
                log.error(str(e))
            else:
                log.debug('Got notification ..{}'.format(
                    str(message.properties['correlation_id'])[-4:]))

                listeners = self.listeners.get(event, [])
                for fn in listeners:
                    self.pool.apply_async(fn, args=(data, ))
        except Exception as e:
            log.error('Unhandled exception in _on_broadcast')
            traceback.print_exc()
Esempio n. 7
0
 def _on_message(self, message):
     """
     Called when a message is received on one of the queues.
     """
     log.debug('Received message %s', message)
     self.pool.apply(self._validate_message, args=(message, ))