예제 #1
0
    def __init__(self, topic, channel, timeout=None, concurrency=1,
                 message_preprocessor=None, service_name=get_random_string()):

        """Wrapper around nsqworker.ThreadWorker
        """
        super(NSQHandler, self).__init__()
        self.logger = self.__class__.get_logger()
        self.io_loop = ioloop.IOLoop.instance()
        self.topic = topic
        self.channel = channel
        self.locker = _locker.RedisLocker(service_name, self.logger)

        self._message_preprocessor = message_preprocessor if message_preprocessor else _identity

        self._persistor = MessagePersistor(self.logger)

        ThreadWorker(
            message_handler=self.handle_message,
            exception_handler=self.handle_exception,
            timeout=timeout,
            concurrency=concurrency,
            topic=topic, channel=channel, **kwargs
        ).subscribe_worker()
예제 #2
0
class NSQHandler(NSQWriter):
    def __init__(self, topic, channel, timeout=None, concurrency=1,
                 message_preprocessor=None, service_name=get_random_string()):

        """Wrapper around nsqworker.ThreadWorker
        """
        super(NSQHandler, self).__init__()
        self.logger = self.__class__.get_logger()
        self.io_loop = ioloop.IOLoop.instance()
        self.topic = topic
        self.channel = channel
        self.locker = _locker.RedisLocker(service_name, self.logger)

        self._message_preprocessor = message_preprocessor if message_preprocessor else _identity

        self._persistor = MessagePersistor(self.logger)

        ThreadWorker(
            message_handler=self.handle_message,
            exception_handler=self.handle_exception,
            timeout=timeout,
            concurrency=concurrency,
            topic=topic, channel=channel, **kwargs
        ).subscribe_worker()

        # self.routes = []

    @classmethod
    def get_logger(cls, name=None):
        logger = logging.getLogger(name or cls.__name__)
        if not logger.handlers:
            formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

            handler = logging.StreamHandler(stream=sys.stdout)
            handler.setFormatter(formatter)
            handler.setLevel(logging.INFO)

            logger.addHandler(handler)
            logger.setLevel(logging.INFO)
            logger.propagate = 0

        return logger

    @classmethod
    def register_route(cls, matcher_func, handler_func):
        """Register route
        """
        if getattr(cls, "routes", None) is None:
            cls.routes = []

        # Don't use bound methods - convert to bare function
        if getattr(handler_func, "im_self", None) is not None:
            handler_func = handler_func.__func__

        cls.routes.append((matcher_func, handler_func))

    def route_message(self, message):
        """Basic message router

        Handlers for the same route will be run sequentially

        type message: nsq.Message
        """
        m_body = message.body
        handlers = []

        for matcher_func, handler_func in self.__class__.routes:

            if matcher_func(m_body) is True:
                handlers.append(handler_func)

        if len(handlers) == 0:
            self.logger.debug("No handlers found for message {}.".format(message.body))
            return

        event_name = "<undefined>"
        jsn = None
        try:
            jsn = json.loads(m_body)
            event_name = jsn['name']
        except Exception:
            pass

        handler_id = gen_random_string()

        self.logger.info("[{}] [Handling new event] [topic={}] [channel={}] [event={}]".format(
            handler_id, self.topic, self.channel, event_name
        ))

        for handler in handlers:
            status = "OK"
            route_id = gen_random_string()

            if jsn is not None and self._persistor.is_persisted_message(jsn):
                if self._persistor.is_route_message(jsn, self.channel, handler.__name__):

                    self.logger.info("[{}] Route {} in channel {} will handle persisted message".format(
                        route_id, handler.__name__, self.channel
                    ))

                else:
                    continue

            self.logger.info("[{}] [START] Routing message to handler [route={}] [event={}]".format(
                route_id, handler.__name__, event_name)
            )
            start_time = current_milli_time()
            try:

                handler(self, self._message_preprocessor(message))

            except Exception as e:
                status = "FAILED"
                msg = "[{}] Handler {} failed handling message {} with error {}".format(
                    route_id, handler.__name__, message.body, e.message)
                self.logger.error(msg)
                self.handle_exception(message, e)

                if self._persistor.enabled:
                    new = self._persistor.persist_message(self.topic, self.channel, handler.__name__, m_body, repr(e))
                    if new:
                        self.logger.info("[{}] Persisted failed message".format(route_id))
                    else:
                        self.logger.info("[{}] Updated existing failed message".format(route_id))

            self.logger.info("[{}] [END] [route={}] [event={}] [status={}] [time={}] ".format(
                route_id, handler.__name__, event_name, status, str(current_milli_time() - start_time))
            )

        self.logger.info("[{}] [DONE handling new event] [topic={}] [channel={}] [event={}]".format(
            handler_id, self.topic, self.channel, event_name
        ))

    def handle_message(self, message):
        """
        Basic message handler
        :type message: nsq.Message
        """

        self.logger.debug("Received message: {}".format(message.body))
        self.route_message(message)
        self.logger.debug("Finished handling message: {}".format(message.body))

    def handle_exception(self, message, e):
        """
        Basic error handler
        :type message: nsq.Message
        :type e: Exception
        """
        error = "message raised an exception: {}. Message body: {}".format(e, message.body)
        self.logger.error(error)
        self.logger.error(traceback.format_exc())