Как регистрировать исключения, возникающие в задаче django celery - программирование
Подтвердить что ты не робот

Как регистрировать исключения, возникающие в задаче django celery

Я установил сельдерей для работы с моим приложением django, используя их инструкции демонализации (http://docs.celeryproject.org/en/latest/tutorials/daemonizing.html#daemonizing)

Вот моя тестовая задача

@periodic_task(run_every=timedelta(seconds=10))
def debugger():
    logger.info("Running debugger")
    raise Exception('Failed')

Мне нужно знать, что эта задача (отладчик) не удалась из-за исключения. Файл журнала сельдерей печатает журнал logger.info( "работает отладчик" ), но он не регистрирует исключение. Я что-то упускаю, или я должен найти неудачные задачи каким-то другим способом?

4b9b3361

Ответ 1

Вы можете посмотреть Руководство пользователя сельдерея:

from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

@app.task
def div():
    try:
        1 / 0
    except ZeroDivisionError:
        logger.exception("Task error")

Из документации для модуля протоколирования python:

Logger.exception(msg, * args)

Записывает сообщение с уровнем ERROR на этом регистраторе. Аргументы интерпретируются как для debug(). Информация об исключении добавляется в сообщение регистрации. Этот метод следует вызывать только из обработчика исключений.

Ответ 2

Вопрос:

Я бы хотел, чтобы сельдерей поймал исключения и записал их в файл журнала, вместо того, чтобы, по-видимому, усвоить их...

Текущий верхний ответ здесь так-то для профессионального решения. Многие разработчики python будут рассматривать скрытую ошибку при каждом случае на красном флаге. Разумное отвращение к этому было хорошо сформулировано в комментарии:

Подождите, я бы ожидал, что в журнале работ будет что-то зарегистрировано, по крайней мере, для каждой неудавшейся задачи...

Сельдерей действительно ломает исключение, он просто не делает то, что OP хочет от него сделать (он хранит его в бэкэнде результата). Следующий пример - лучший интернет, который может предложить по этой проблеме. Он немного устарел, но обратите внимание на количество вилок и звезд.

https://gist.github.com/darklow/c70a8d1147f05be877c3

Суть в том, что он делает ошибку и делает с ней что-то обычное. Это надмножество проблемы ОП. Вот как настроить решение в gist для регистрации исключения.

import logging

logger = logging.getLogger('your.desired.logger')


class LogErrorsTask(Task):
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        logger.exception('Celery task failure!!!1', exc_info=exc)
        super(LogErrorsTask, self).on_failure(exc, task_id, args, kwargs, einfo)

Вам все равно нужно убедиться, что все ваши задачи наследуются от этого класса задач, а сам gist показывает, как это сделать, если вы используете декоратор @taskbase=LogErrorsTask kwarg).

Преимущество этого решения состоит в том, чтобы не встраивать ваш код в какие-либо дополнительные контексты, отличные от try-except. Это согласуется с кодом кода отказа, который сельдерей уже использует.

Ответ 3

Используйте модуль трассировки, чтобы захватить трассировку в виде строки и отправить ее в журнал.

try:
    ...
except:
    import traceback
    logger.info(traceback.format_exc())

Ответ 4

Вы также можете переопределить приложение celery, чтобы не добавлять base kwarg к каждому декоратору @app.task:

import logging
from celery import Celery, Task

logger = logging.getLogger(__name__)

class LoggingTask(Task):
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        logger.exception('Task failed: %s' % exc, exc_info=exc)
        super(LoggingTask, self).on_failure(exc, task_id, args, kwargs, einfo)

class LoggingCelery(Celery):
    def task(self, *args, **kwargs):
        kwargs.setdefault('base', LoggingTask)
        return super(LoggingCelery, self).task(*args, **kwargs)

app = LoggingCelery(__name__)