Подтвердить что ты не робот

Мониторинг исключений gevent на рабочих местах

Я создаю приложение, используя gevent. Мое приложение становится довольно большим, так как есть много рабочих мест, которые порождаются и уничтожаются. Теперь я заметил, что когда одно из этих заданий падает, все мое приложение просто продолжает работать (если исключение исходит из не главной озелени), что хорошо. Но проблема в том, что я должен посмотреть на свою консоль, чтобы увидеть ошибку. Поэтому часть моего приложения может "умереть", и я не сразу понимаю об этом, и приложение продолжает работать.

Jittering моего приложения с помощью try catch does not кажется чистым решением. Может быть, пользовательская функция spawn, которая сообщает об ошибках?

Каков надлежащий способ мониторинга рабочих мест/зеленых насаждений? исключения catch?

В моем случае я слушаю события из нескольких разных источников, и я должен разбираться с каждым другим. Очень важны 5 рабочих мест. Зеленая веб-серверная, зеленая веб-карта, базы данных, зеленой очереди и zmq greenlet. Если какая-либо из этих "штампов" моя заявка должна полностью погибнуть. Другие рабочие места, которые умирают, не так важны. Например, возможно, что зелень websocket умирает из-за какого-то исключения, и остальные приложения продолжают работать нормально, как ничего не произошло. Сейчас это абсолютно бесполезно и опасно, и нужно просто тяжело врезаться.

4b9b3361

Ответ 1

Я думаю, что самый чистый способ - поймать исключение, которое вы считаете фатальным, и сделать sys.exit() (вам понадобится gevent 1.0, так как до этого SystemExit не выйти из процесса).

Другим способом является использование link_exception, которое будет вызываться, если зелень умерла с исключением.

spawn(important_greenlet).link_exception(lambda *args: sys.exit("important_greenlet died"))

Обратите внимание, что для этого вам также понадобится gevent 1.0.

Если на 0.13.6 сделайте что-то вроде этого, чтобы убить процесс:

gevent.get_hub().parent.throw(SystemExit())

Ответ 2

Вы хотите greenlet.link_exception() все свои зеленые насадки на функцию janitor.

Функция janitor будет передана любой зеленой, которая умирает, из которой она может проверить ее greenlet.exception, чтобы узнать, что произошло, и при необходимости что-то об этом.

Ответ 3

Как сказал @Denis и @lvo, link_exception в порядке, но я думаю, что для этого будет лучший способ, без изменения вашего текущего кода, чтобы создать зеленую букву.

Как правило, всякий раз, когда исключение выбрасывается в зеленую оболочку, для этой родословной будет вызываться метод _report_errorgevent.greenlet.Greenlet). Он будет выполнять некоторые функции, такие как вызов всех функций связи и, наконец, вызов self.parent.handle_error с exc_info из текущего стека. self.parent здесь - глобальный объект Hub, это означает, что все исключения, произошедшие в каждой зелене, всегда будут централизованы для одного метода обработки. По умолчанию Hub.handle_error различают тип исключения, игнорируют какой-то тип и печатают другие (что мы всегда видели в консоли).

Исправив метод Hub.handle_error, мы можем легко зарегистрировать наши собственные обработчики ошибок и больше не потерять ошибку. Я написал вспомогательную функцию, чтобы это произошло:

from gevent.hub import Hub


IGNORE_ERROR = Hub.SYSTEM_ERROR + Hub.NOT_ERROR


def register_error_handler(error_handler):

    Hub._origin_handle_error = Hub.handle_error

    def custom_handle_error(self, context, type, value, tb):
        if not issubclass(type, IGNORE_ERROR):
            # print 'Got error from greenlet:', context, type, value, tb
            error_handler(context, (type, value, tb))

        self._origin_handle_error(context, type, value, tb)

    Hub.handle_error = custom_handle_error

Чтобы использовать его, просто вызовите его до инициализации цикла события:

def gevent_error_handler(context, exc_info):
    """Here goes your custom error handling logics"""
    e = exc_info[1]
    if isinstance(e, SomeError):
        # do some notify things
        pass
    sentry_client.captureException(exc_info=exc_info)

register_error_handler(gevent_error_handler)

Это решение было протестировано в соответствии с gevent 1.0.2 и 1.1b3, мы используем его для отправки информации об ошибке greenlet в watchry (система отслеживания исключений), она работает довольно хорошо до сих пор.

Ответ 4

Основная проблема с greenlet.link_exception() заключается в том, что она не предоставляет никакой информации о трассировке, которая может быть очень важна для регистрации.

Для ведения журнала с трассировкой я использую декоратор, чтобы разворачивать задания, которые косвенные вызовы задаются в простой функции регистрации:

from functools import wraps    

import gevent

def async(wrapped):

    def log_exc(func):

        @wraps(wrapped)
        def wrapper(*args, **kwargs):
            try:
                func(*args, **kwargs)
            except Exception:
                log.exception('%s', func)
        return wrapper

    @wraps(wrapped)
    def wrapper(*args, **kwargs):
        greenlet = gevent.spawn(log_exc(wrapped), *args, **kwargs)

    return wrapper

Конечно, вы можете добавить вызов link_exception для управления заданиями (которые мне не нужны)