예제 #1
0
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(self.redis,
                                            self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(self.redis,
                                              self.config['outbound_ttl'])

        self.message_rate = MessageRateStore(self.redis)

        if self.config.get('message_queue') is not None:
            self.ro_connector = yield self.setup_ro_connector(
                self.config['message_queue'])
            self.ro_connector.set_outbound_handler(self._publish_message)
예제 #2
0
    def setup(self, redis=None, message_sender=None):
        if redis is None:
            redis = yield TxRedisManager.from_config(self.redis_config)

        if message_sender is None:
            message_sender = MessageSender('amqp-spec-0-8.xml',
                                           self.amqp_config)

        self.redis = redis
        self.message_sender = message_sender
        self.message_sender.setServiceParent(self.service)

        self.inbounds = InboundMessageStore(self.redis,
                                            self.config.inbound_message_ttl)

        self.outbounds = OutboundMessageStore(self.redis,
                                              self.config.outbound_message_ttl)

        self.message_rate = MessageRateStore(self.redis)

        self.plugins = []
        for plugin_config in self.config.plugins:
            cls = load_class_by_string(plugin_config['type'])
            plugin = cls()
            yield plugin.start_plugin(plugin_config, self.config)
            self.plugins.append(plugin)

        yield Channel.start_all_channels(self.redis, self.config, self.service,
                                         self.plugins)
예제 #3
0
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(
            self.redis, self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(
            self.redis, self.config['outbound_ttl'])
예제 #4
0
파일: workers.py 프로젝트: praekelt/junebug
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(
            self.redis, self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(
            self.redis, self.config['outbound_ttl'])

        self.message_rate = MessageRateStore(self.redis)

        if self.config.get('message_queue') is not None:
            self.ro_connector = yield self.setup_ro_connector(
                self.config['message_queue'])
            self.ro_connector.set_outbound_handler(
                self._publish_message)
예제 #5
0
class MessageForwardingWorker(ApplicationWorker):
    '''This application worker consumes vumi messages placed on a configured
    amqp queue, and sends them as HTTP requests with a JSON body to a
    configured URL'''
    CONFIG_CLASS = MessageForwardingConfig

    @inlineCallbacks
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(self.redis,
                                            self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(self.redis,
                                              self.config['outbound_ttl'])

        self.message_rate = MessageRateStore(self.redis)

        if self.config.get('message_queue') is not None:
            self.ro_connector = yield self.setup_ro_connector(
                self.config['message_queue'])
            self.ro_connector.set_outbound_handler(self._publish_message)

    @inlineCallbacks
    def teardown_application(self):
        yield self.redis.close_manager()

    @property
    def channel_id(self):
        return self.config['transport_name']

    @inlineCallbacks
    def consume_user_message(self, message):
        '''Sends the vumi message as an HTTP request to the configured URL'''
        yield self.inbounds.store_vumi_message(self.channel_id, message)

        msg = api_from_message(message)

        if self.config.get('mo_message_url') is not None:
            resp = yield post(self.config['mo_message_url'], msg)
            if request_failed(resp):
                logging.exception(
                    'Error sending message, received HTTP code %r with body %r'
                    '. Message: %r' % (resp.code, (yield resp.content()), msg))

        if self.config.get('message_queue') is not None:
            yield self.ro_connector.publish_inbound(message)

        yield self._increment_metric('inbound')

    @inlineCallbacks
    def store_and_forward_event(self, event):
        '''Store the event in the message store, POST it to the correct
        URL.'''
        yield self._store_event(event)
        yield self._forward_event(event)
        yield self._count_event(event)

    def _increment_metric(self, label):
        return self.message_rate.increment(self.channel_id, label,
                                           self.config['metric_window'])

    def _count_event(self, event):
        if event['event_type'] == 'ack':
            return self._increment_metric('submitted')
        if event['event_type'] == 'nack':
            return self._increment_metric('rejected')
        if event['event_type'] == 'delivery_report':
            if event['delivery_status'] == 'pending':
                return self._increment_metric('delivery_pending')
            if event['delivery_status'] == 'failed':
                return self._increment_metric('delivery_failed')
            if event['delivery_status'] == 'delivered':
                return self._increment_metric('delivery_succeeded')

    def _store_event(self, event):
        '''Stores the event in the message store'''
        message_id = event['user_message_id']
        return self.outbounds.store_event(self.channel_id, message_id, event)

    @inlineCallbacks
    def _forward_event(self, event):
        '''Forward the event to the correct places.'''
        yield self._forward_event_http(event)
        yield self._forward_event_amqp(event)

    @inlineCallbacks
    def _forward_event_http(self, event):
        '''POST the event to the correct URL'''
        url = yield self._get_event_url(event)

        if url is None:
            return

        msg = api_from_event(self.channel_id, event)

        if msg['event_type'] is None:
            logging.exception("Discarding unrecognised event %r" % (event, ))
            return

        resp = yield post(url, msg)

        if request_failed(resp):
            logging.exception(
                'Error sending event, received HTTP code %r with body %r. '
                'Event: %r' % (resp.code, (yield resp.content()), event))

    def _forward_event_amqp(self, event):
        '''Put the event on the correct queue.'''
        if self.config.get('message_queue') is not None:
            return self.ro_connector.publish_event(event)

    def consume_ack(self, event):
        return self.store_and_forward_event(event)

    def consume_nack(self, event):
        return self.store_and_forward_event(event)

    def consume_delivery_report(self, event):
        return self.store_and_forward_event(event)

    def _get_event_url(self, event):
        msg_id = event['user_message_id']
        return self.outbounds.load_event_url(self.channel_id, msg_id)
예제 #6
0
파일: workers.py 프로젝트: praekelt/junebug
class MessageForwardingWorker(ApplicationWorker):
    '''This application worker consumes vumi messages placed on a configured
    amqp queue, and sends them as HTTP requests with a JSON body to a
    configured URL'''
    CONFIG_CLASS = MessageForwardingConfig

    @inlineCallbacks
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(
            self.redis, self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(
            self.redis, self.config['outbound_ttl'])

        self.message_rate = MessageRateStore(self.redis)

        if self.config.get('message_queue') is not None:
            self.ro_connector = yield self.setup_ro_connector(
                self.config['message_queue'])
            self.ro_connector.set_outbound_handler(
                self._publish_message)

    @inlineCallbacks
    def teardown_application(self):
        if getattr(self, 'redis', None) is not None:
            yield self.redis.close_manager()

    @property
    def channel_id(self):
        return self.config['transport_name']

    @inlineCallbacks
    def consume_user_message(self, message):
        '''Sends the vumi message as an HTTP request to the configured URL'''
        yield self.inbounds.store_vumi_message(self.channel_id, message)

        msg = api_from_message(message)

        if self.config.get('mo_message_url') is not None:
            config = self.get_static_config()

            (url, auth) = self._split_url_and_credentials(
                config.mo_message_url)

            # Construct token auth headers if configured
            auth_token = config.mo_message_url_auth_token
            if auth_token:
                headers = {
                    'Authorization': [
                        'Token %s' % (auth_token,)]
                }
            else:
                headers = {}

            resp = yield post(url, msg,
                              timeout=config.mo_message_url_timeout,
                              auth=auth, headers=headers)
            if resp and request_failed(resp):
                logging.exception(
                    'Error sending message, received HTTP code %r with body %r'
                    '. Message: %r' % (resp.code, (yield resp.content()), msg))

        if self.config.get('message_queue') is not None:
            yield self.ro_connector.publish_inbound(message)

        yield self._increment_metric('inbound')

    @inlineCallbacks
    def store_and_forward_event(self, event):
        '''Store the event in the message store, POST it to the correct
        URL.'''
        yield self._store_event(event)
        yield self._forward_event(event)
        yield self._count_event(event)

    def _increment_metric(self, label):
        return self.message_rate.increment(
            self.channel_id, label, self.config['metric_window'])

    def _count_event(self, event):
        if event['event_type'] == 'ack':
            return self._increment_metric('submitted')
        if event['event_type'] == 'nack':
            return self._increment_metric('rejected')
        if event['event_type'] == 'delivery_report':
            if event['delivery_status'] == 'pending':
                return self._increment_metric('delivery_pending')
            if event['delivery_status'] == 'failed':
                return self._increment_metric('delivery_failed')
            if event['delivery_status'] == 'delivered':
                return self._increment_metric('delivery_succeeded')

    def _store_event(self, event):
        '''Stores the event in the message store'''
        message_id = event['user_message_id']
        if message_id is None:
            logging.warning(
                "Cannot store event, missing user_message_id: %r" % event)
        else:
            return self.outbounds.store_event(
                self.channel_id, message_id, event)

    @inlineCallbacks
    def _forward_event(self, event):
        '''Forward the event to the correct places.'''
        yield self._forward_event_http(event)
        yield self._forward_event_amqp(event)

    @inlineCallbacks
    def _forward_event_http(self, event):
        '''POST the event to the correct URL'''
        url = yield self._get_event_url(event)

        if url is None:
            return

        (url, auth) = self._split_url_and_credentials(urlparse(url))

        # Construct token auth headers if configured
        auth_token = yield self._get_event_auth_token(event)

        if auth_token:
            headers = {
                'Authorization': [
                    'Token %s' % (auth_token,)]
            }
        else:
            headers = {}

        msg = api_from_event(self.channel_id, event)

        if msg['event_type'] is None:
            logging.exception("Discarding unrecognised event %r" % (event,))
            return

        config = self.get_static_config()
        resp = yield post(url, msg, timeout=config.event_url_timeout,
                          auth=auth, headers=headers)

        if resp and request_failed(resp):
            logging.exception(
                'Error sending event, received HTTP code %r with body %r. '
                'Event: %r' % (resp.code, (yield resp.content()), event))

    def _forward_event_amqp(self, event):
        '''Put the event on the correct queue.'''
        if self.config.get('message_queue') is not None:
            return self.ro_connector.publish_event(event)

    def consume_ack(self, event):
        return self.store_and_forward_event(event)

    def consume_nack(self, event):
        return self.store_and_forward_event(event)

    def consume_delivery_report(self, event):
        return self.store_and_forward_event(event)

    def _split_url_and_credentials(self, url):
        # Parse the basic auth username & password if available
        username = url.username
        password = url.password
        if any([username, password]):
            url = urlunparse((
                url.scheme,
                '%s%s' % (url.hostname, (':%s' % (url.port,)
                                         if url.port is not None else '')),
                url.path,
                url.params,
                url.query,
                url.fragment,
            ))
            auth = (username, password)
            return (url, auth)
        return (url.geturl(), None)

    def _get_event_url(self, event):
        msg_id = event['user_message_id']
        if msg_id is not None:
            return self.outbounds.load_event_url(self.channel_id, msg_id)
        else:
            logging.warning(
                "Cannot find event URL, missing user_message_id: %r" % event)

    def _get_event_auth_token(self, event):
        msg_id = event['user_message_id']
        if msg_id is not None:
            return self.outbounds.load_event_auth_token(
                self.channel_id, msg_id)
        else:
            logging.warning(
                "Cannot find event auth, missing user_message_id: %r" % event)
예제 #7
0
class MessageForwardingWorker(ApplicationWorker):
    '''This application worker consumes vumi messages placed on a configured
    amqp queue, and sends them as HTTP requests with a JSON body to a
    configured URL'''
    CONFIG_CLASS = MessageForwardingConfig

    @inlineCallbacks
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(self.redis,
                                            self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(self.redis,
                                              self.config['outbound_ttl'])

        self.message_rate = MessageRateStore(self.redis)

        if self.config.get('message_queue') is not None:
            self.ro_connector = yield self.setup_ro_connector(
                self.config['message_queue'])
            self.ro_connector.set_outbound_handler(self._publish_message)

    @inlineCallbacks
    def teardown_application(self):
        if getattr(self, 'redis', None) is not None:
            yield self.redis.close_manager()

    @property
    def channel_id(self):
        return self.config['transport_name']

    @inlineCallbacks
    def consume_user_message(self, message):
        '''Sends the vumi message as an HTTP request to the configured URL'''
        yield self.inbounds.store_vumi_message(self.channel_id, message)

        msg = api_from_message(message)

        if self.config.get('mo_message_url') is not None:
            config = self.get_static_config()

            # Parse the basic auth username & password if available
            username = config.mo_message_url.username
            password = config.mo_message_url.password
            if any([username, password]):
                url = urlunparse((
                    config.mo_message_url.scheme,
                    '%s%s' %
                    (config.mo_message_url.hostname,
                     (':%s' % (config.mo_message_url.port, )
                      if config.mo_message_url.port is not None else '')),
                    config.mo_message_url.path,
                    config.mo_message_url.params,
                    config.mo_message_url.query,
                    config.mo_message_url.fragment,
                ))
                auth = (username, password)
            else:
                url = config.mo_message_url.geturl()
                auth = None

            # Construct token auth headers if configured
            auth_token = config.mo_message_url_auth_token
            if auth_token:
                headers = {'Authorization': ['Token %s' % (auth_token, )]}
            else:
                headers = {}

            resp = yield post(url,
                              msg,
                              timeout=config.mo_message_url_timeout,
                              auth=auth,
                              headers=headers)
            if resp and request_failed(resp):
                logging.exception(
                    'Error sending message, received HTTP code %r with body %r'
                    '. Message: %r' % (resp.code, (yield resp.content()), msg))

        if self.config.get('message_queue') is not None:
            yield self.ro_connector.publish_inbound(message)

        yield self._increment_metric('inbound')

    @inlineCallbacks
    def store_and_forward_event(self, event):
        '''Store the event in the message store, POST it to the correct
        URL.'''
        yield self._store_event(event)
        yield self._forward_event(event)
        yield self._count_event(event)

    def _increment_metric(self, label):
        return self.message_rate.increment(self.channel_id, label,
                                           self.config['metric_window'])

    def _count_event(self, event):
        if event['event_type'] == 'ack':
            return self._increment_metric('submitted')
        if event['event_type'] == 'nack':
            return self._increment_metric('rejected')
        if event['event_type'] == 'delivery_report':
            if event['delivery_status'] == 'pending':
                return self._increment_metric('delivery_pending')
            if event['delivery_status'] == 'failed':
                return self._increment_metric('delivery_failed')
            if event['delivery_status'] == 'delivered':
                return self._increment_metric('delivery_succeeded')

    def _store_event(self, event):
        '''Stores the event in the message store'''
        message_id = event['user_message_id']
        if message_id is None:
            logging.warning("Cannot store event, missing user_message_id: %r" %
                            event)
        else:
            return self.outbounds.store_event(self.channel_id, message_id,
                                              event)

    @inlineCallbacks
    def _forward_event(self, event):
        '''Forward the event to the correct places.'''
        yield self._forward_event_http(event)
        yield self._forward_event_amqp(event)

    @inlineCallbacks
    def _forward_event_http(self, event):
        '''POST the event to the correct URL'''
        url = yield self._get_event_url(event)

        if url is None:
            return

        msg = api_from_event(self.channel_id, event)

        if msg['event_type'] is None:
            logging.exception("Discarding unrecognised event %r" % (event, ))
            return

        config = self.get_static_config()
        resp = yield post(url, msg, timeout=config.event_url_timeout)

        if resp and request_failed(resp):
            logging.exception(
                'Error sending event, received HTTP code %r with body %r. '
                'Event: %r' % (resp.code, (yield resp.content()), event))

    def _forward_event_amqp(self, event):
        '''Put the event on the correct queue.'''
        if self.config.get('message_queue') is not None:
            return self.ro_connector.publish_event(event)

    def consume_ack(self, event):
        return self.store_and_forward_event(event)

    def consume_nack(self, event):
        return self.store_and_forward_event(event)

    def consume_delivery_report(self, event):
        return self.store_and_forward_event(event)

    def _get_event_url(self, event):
        msg_id = event['user_message_id']
        if msg_id is not None:
            return self.outbounds.load_event_url(self.channel_id, msg_id)
        else:
            logging.warning(
                "Cannot find event URL, missing user_message_id: %r" % event)
예제 #8
0
 def create_store(self, ttl=60):
     redis = yield self.get_redis()
     store = InboundMessageStore(redis, ttl)
     returnValue(store)
예제 #9
0
class MessageForwardingWorker(ApplicationWorker):
    '''This application worker consumes vumi messages placed on a configured
    amqp queue, and sends them as HTTP requests with a JSON body to a
    configured URL'''
    CONFIG_CLASS = MessageForwardingConfig

    @inlineCallbacks
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(
            self.redis, self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(
            self.redis, self.config['outbound_ttl'])

        self.message_rate = MessageRateStore(self.redis)

        if self.config.get('message_queue') is not None:
            self.ro_connector = yield self.setup_ro_connector(
                self.config['message_queue'])
            self.ro_connector.set_outbound_handler(
                self._publish_message)

    @inlineCallbacks
    def teardown_application(self):
        yield self.redis.close_manager()

    @property
    def channel_id(self):
        return self.config['transport_name']

    @inlineCallbacks
    def consume_user_message(self, message):
        '''Sends the vumi message as an HTTP request to the configured URL'''
        yield self.inbounds.store_vumi_message(self.channel_id, message)

        msg = api_from_message(message)

        if self.config.get('mo_message_url') is not None:
            resp = yield post(self.config['mo_message_url'], msg)
            if request_failed(resp):
                logging.exception(
                    'Error sending message, received HTTP code %r with body %r'
                    '. Message: %r' % (resp.code, (yield resp.content()), msg))

        if self.config.get('message_queue') is not None:
            yield self.ro_connector.publish_inbound(message)

        yield self._increment_metric('inbound')

    @inlineCallbacks
    def store_and_forward_event(self, event):
        '''Store the event in the message store, POST it to the correct
        URL.'''
        yield self._store_event(event)
        yield self._forward_event(event)
        yield self._count_event(event)

    def _increment_metric(self, label):
        return self.message_rate.increment(
            self.channel_id, label, self.config['metric_window'])

    def _count_event(self, event):
        if event['event_type'] == 'ack':
            return self._increment_metric('submitted')
        if event['event_type'] == 'nack':
            return self._increment_metric('rejected')
        if event['event_type'] == 'delivery_report':
            if event['delivery_status'] == 'pending':
                return self._increment_metric('delivery_pending')
            if event['delivery_status'] == 'failed':
                return self._increment_metric('delivery_failed')
            if event['delivery_status'] == 'delivered':
                return self._increment_metric('delivery_succeeded')

    def _store_event(self, event):
        '''Stores the event in the message store'''
        message_id = event['user_message_id']
        return self.outbounds.store_event(self.channel_id, message_id, event)

    @inlineCallbacks
    def _forward_event(self, event):
        '''Forward the event to the correct places.'''
        yield self._forward_event_http(event)
        yield self._forward_event_amqp(event)

    @inlineCallbacks
    def _forward_event_http(self, event):
        '''POST the event to the correct URL'''
        url = yield self._get_event_url(event)

        if url is None:
            return

        msg = api_from_event(self.channel_id, event)

        if msg['event_type'] is None:
            logging.exception("Discarding unrecognised event %r" % (event,))
            return

        resp = yield post(url, msg)

        if request_failed(resp):
            logging.exception(
                'Error sending event, received HTTP code %r with body %r. '
                'Event: %r' % (resp.code, (yield resp.content()), event))

    def _forward_event_amqp(self, event):
        '''Put the event on the correct queue.'''
        if self.config.get('message_queue') is not None:
            return self.ro_connector.publish_event(event)

    def consume_ack(self, event):
        return self.store_and_forward_event(event)

    def consume_nack(self, event):
        return self.store_and_forward_event(event)

    def consume_delivery_report(self, event):
        return self.store_and_forward_event(event)

    def _get_event_url(self, event):
        msg_id = event['user_message_id']
        return self.outbounds.load_event_url(self.channel_id, msg_id)
예제 #10
0
class MessageForwardingWorker(ApplicationWorker):
    '''This application worker consumes vumi messages placed on a configured
    amqp queue, and sends them as HTTP requests with a JSON body to a
    configured URL'''
    CONFIG_CLASS = MessageForwardingConfig

    @inlineCallbacks
    def setup_application(self):
        self.redis = yield TxRedisManager.from_config(
            self.config['redis_manager'])

        self.inbounds = InboundMessageStore(
            self.redis, self.config['inbound_ttl'])

        self.outbounds = OutboundMessageStore(
            self.redis, self.config['outbound_ttl'])

    @inlineCallbacks
    def teardown_application(self):
        yield self.redis.close_manager()

    @property
    def channel_id(self):
        return self.config['transport_name']

    @inlineCallbacks
    def consume_user_message(self, message):
        '''Sends the vumi message as an HTTP request to the configured URL'''
        yield self.inbounds.store_vumi_message(self.channel_id, message)

        msg = api_from_message(message)
        resp = yield post(self.config['mo_message_url'], msg)

        if request_failed(resp):
            logging.exception(
                'Error sending message, received HTTP code %r with body %r. '
                'Message: %r' % (resp.code, (yield resp.content()), msg))

    @inlineCallbacks
    def forward_event(self, event):
        url = yield self._get_event_url(event)

        if url is None:
            return

        msg = api_from_event(self.channel_id, event)

        if msg['event_type'] is None:
            logging.exception("Discarding unrecognised event %r" % (event,))
            return

        resp = yield post(url, msg)

        if request_failed(resp):
            logging.exception(
                'Error sending event, received HTTP code %r with body %r. '
                'Event: %r' % (resp.code, (yield resp.content()), event))

    def consume_ack(self, event):
        return self.forward_event(event)

    def consume_nack(self, event):
        return self.forward_event(event)

    def consume_delivery_report(self, event):
        return self.forward_event(event)

    def _get_event_url(self, event):
        msg_id = event['user_message_id']
        return self.outbounds.load_event_url(self.channel_id, msg_id)