How to make a celery task fail from within the task?

后端 未结 3 975
忘掉有多难
忘掉有多难 2021-02-05 00:37

Under some conditions, I want to make a celery task fail from within that task. I tried the following:

from celery.task import task
from celery import states

@t         


        
相关标签:
3条回答
  • 2021-02-05 01:19

    I'd like to further expand on Pierre's answer as I've encountered some issues using the suggested solution.

    To allow custom fields when updating a task's state to states.FAILURE, it is important to also mock some attributes that a FAILURE state would have (notice exc_type and exc_message) While the solution will terminate the task, any attempt to query the state (For example - to fetch the 'REASON FOR FAILURE' value) will fail.

    Below is a snippet for reference I took from: https://www.distributedpython.com/2018/09/28/celery-task-states/

    @app.task(bind=True)
    def task(self):
        try:
            raise ValueError('Some error')
        except Exception as ex:
            self.update_state(
                state=states.FAILURE,
                meta={
                    'exc_type': type(ex).__name__,
                    'exc_message': traceback.format_exc().split('\n')
                    'custom': '...'
                })
            raise Ignore()
    
    0 讨论(0)
  • 2021-02-05 01:21

    I got an interesting reply on this question from Ask Solem, where he proposes an 'after_return' handler to solve the issue. This might be an interesting option for the future.

    In the meantime I solved the issue by simply returning a string 'FAILURE' from the task when I want to make it fail and then checking for that as follows:

    result = AsyncResult(task_id)
    if result.state == 'FAILURE' or (result.state == 'SUCCESS' and result.get() == 'FAILURE'):
        # Failure processing task 
    
    0 讨论(0)
  • 2021-02-05 01:32

    To mark a task as failed without raising an exception, update the task state to FAILURE and then raise an Ignore exception, because returning any value will record the task as successful, an example:

    from celery import Celery, states
    from celery.exceptions import Ignore
    
    app = Celery('tasks', broker='amqp://guest@localhost//')
    
    @app.task(bind=True)
    def run_simulation(self):
        if some_condition:
            # manually update the task state
            self.update_state(
                state = states.FAILURE,
                meta = 'REASON FOR FAILURE'
            )
    
            # ignore the task so no other state is recorded
            raise Ignore()
    

    But the best way is to raise an exception from your task, you can create a custom exception to track these failures:

    class TaskFailure(Exception):
       pass
    

    And raise this exception from your task:

    if some_condition:
        raise TaskFailure('Failure reason')
    
    0 讨论(0)
提交回复
热议问题