在Django-Celery中停止/清除定期任务

时间:2021-11-08 19:19:06

I have managed to get periodic tasks working in django-celery by subclassing PeriodicTask. I tried to create a test task and set it running doing something useless. It works.

我设法通过继承PeriodicTask来定期在django-celery中工作。我尝试创建一个测试任务并将其设置为运行无用的东西。有用。

Now I can't stop it. I've read the documentation and I cannot find out how to remove the task from the execution queue. I have tried using celeryctl and using the shell, but registry.tasks() is empty, so I can't see how to remove it.

现在我无法阻止它。我已经阅读了文档,但我无法找到如何从执行队列中删除任务。我尝试过使用celeryctl并使用shell,但是registry.tasks()是空的,所以我看不出如何删除它。

I have seen suggestions that I should "revoke" it, but for this I appear to need a task id, and I can't see how I would find the task id.

我已经看到了我应该“撤销”它的建议,但为此我似乎需要一个任务ID,我看不出我将如何找到任务ID。

Thanks.

谢谢。

2 个解决方案

#1


21  

A task is a message, and a "periodic task" sends task messages at periodic intervals. Each of the tasks sent will have an unique id assigned to it.

任务是消息,“周期性任务”以定期间隔发送任务消息。发送的每个任务都将分配一个唯一的ID。

revoke will only cancel a single task message. To get the id for a task you have to keep track of the id sent, but you can also specify a custom id when you send a task.

撤销只会取消单个任务消息。要获取任务的ID,您必须跟踪发送的ID,但您也可以在发送任务时指定自定义ID。

I'm not sure if you want to cancel a single task message, or if you want to stop the periodic task from sending more messages, so I'll list answers for both.

我不确定您是否要取消单个任务消息,或者您是否要停止定期任务发送更多消息,因此我将列出两者的答案。

There is no built-in way to keep the id of a task sent with periodic tasks, but you could set the id for each task to the name of the periodic task, that way the id will refer to any task sent with the periodic task (usually the last one). You can specify a custom id this way,

没有内置的方法来保持使用定期任务发送的任务的id,但是您可以将每个任务的id设置为周期性任务的名称,这样id将引用随周期任务发送的任何任务(通常是最后一个)。您可以通过这种方式指定自定义ID,

either with the @periodic_task decorator:

使用@periodic_task装饰器:

@periodic_task(options={"task_id": "my_periodic_task"})
def my_periodic_task():
    pass

or with the CELERYBEAT_SCHEDULE setting:

或者使用CELERYBEAT_SCHEDULE设置:

CELERYBEAT_SCHEDULE = {name: {"task": task_name,
                              "options": {"task_id": name}}}

If you want to remove a periodic task you simply remove the @periodic_task from the codebase, or remove the entry from CELERYBEAT_SCHEDULE. If you are using the Django database scheduler you have to remove the periodic task from the Django Admin interface.

如果要删除周期性任务,只需从代码库中删除@periodic_task,或从CELERYBEAT_SCHEDULE中删除该条目。如果您使用的是Django数据库调度程序,则必须从Django Admin界面中删除定期任务。

PS1: revoke doesn't stop a task that has already been started. It only cancels tasks that haven't been started yet. You can terminate a running task using revoke(task_id, terminate=True). By default this will send the TERM signal to the process, if you want to send another signal (e.g. KILL) use revoke(task_id, terminate=True, signal="KILL").

PS1:撤销不会停止已经启动的任务。它只取消尚未启动的任务。您可以使用revoke终止正在运行的任务(task_id,terminate = True)。默认情况下,如果要发送另一个信号(例如KILL),则会将TERM信号发送到进程,使用revoke(task_id,terminate = True,signal =“KILL”)。

PS2: revoke is a remote control command so it is only supported by the RabbitMQ and Redis broker transports. If you want your task to support cancellation you should do so by storing a cancelled flag in a database and have the task check that flag when it starts:

PS2:revoke是一个远程控制命令,因此只有RabbitMQ和Redis代理传输支持它。如果您希望您的任务支持取消,您应该通过在数据库中存储取消的标志并让任务在启动时检查该标志来执行此操作:

from celery.task import Task

class RevokeableTask(Task):
    """Task that can be revoked.

    Example usage:

        @task(base=RevokeableTask)
        def mytask():
            pass
    """

    def __call__(self, *args, **kwargs):
        if revoke_flag_set_in_db_for(self.request.id):
            return
        super(RevokeableTask, self).__call__(*args, **kwargs)

#2


3  

Just in case this may help someone ... We had the same problem at work, and despites some efforts to find some kind of management command to remove the periodic task, we could not. So here are some pointers.

以防万一这可能对某人有所帮助......我们在工作中遇到了同样的问题,并且无视某些管理命令来取消定期任务,我们做不到。所以这里有一些指示。

You should probably first double-check which scheduler class you're using.

您可能应该首先仔细检查您正在使用的调度程序类。

The default scheduler is celery.beat.PersistentScheduler, which is simply keeping track of the last run times in a local database file (a shelve).

默认调度程序是celery.beat.PersistentScheduler,它只是跟踪本地数据库文件(搁置)中的最后运行时间。

In our case, we were using the djcelery.schedulers.DatabaseScheduler class.

在我们的例子中,我们使用的是djcelery.schedulers.DatabaseScheduler类。

django-celery also ships with a scheduler that stores the schedule in the Django database

django-celery还附带一个调度程序,用于在Django数据库中存储调度

Although the documentation does mention a way to remove the periodic tasks:

虽然文档确实提到了一种删除周期性任务的方法:

Using django-celery‘s scheduler you can add, modify and remove periodic tasks from the Django Admin.

使用django-celery的调度程序,您可以从Django Admin添加,修改和删除定期任务。

We wanted to perform the removal programmatically, or via a (celery/management) command in a shell.

我们希望以编程方式执行删除,或者通过shell中的(celery / management)命令执行删除。

Since we could not find a command line, we used the django/python shell:

由于我们找不到命令行,我们使用了django / python shell:

$ python manage.py shell
>>> from djcelery.models import PeriodicTask
>>> pt = PeriodicTask.objects.get(name='the_task_name')
>>> pt.delete()

I hope this helps!

我希望这有帮助!

#1


21  

A task is a message, and a "periodic task" sends task messages at periodic intervals. Each of the tasks sent will have an unique id assigned to it.

任务是消息,“周期性任务”以定期间隔发送任务消息。发送的每个任务都将分配一个唯一的ID。

revoke will only cancel a single task message. To get the id for a task you have to keep track of the id sent, but you can also specify a custom id when you send a task.

撤销只会取消单个任务消息。要获取任务的ID,您必须跟踪发送的ID,但您也可以在发送任务时指定自定义ID。

I'm not sure if you want to cancel a single task message, or if you want to stop the periodic task from sending more messages, so I'll list answers for both.

我不确定您是否要取消单个任务消息,或者您是否要停止定期任务发送更多消息,因此我将列出两者的答案。

There is no built-in way to keep the id of a task sent with periodic tasks, but you could set the id for each task to the name of the periodic task, that way the id will refer to any task sent with the periodic task (usually the last one). You can specify a custom id this way,

没有内置的方法来保持使用定期任务发送的任务的id,但是您可以将每个任务的id设置为周期性任务的名称,这样id将引用随周期任务发送的任何任务(通常是最后一个)。您可以通过这种方式指定自定义ID,

either with the @periodic_task decorator:

使用@periodic_task装饰器:

@periodic_task(options={"task_id": "my_periodic_task"})
def my_periodic_task():
    pass

or with the CELERYBEAT_SCHEDULE setting:

或者使用CELERYBEAT_SCHEDULE设置:

CELERYBEAT_SCHEDULE = {name: {"task": task_name,
                              "options": {"task_id": name}}}

If you want to remove a periodic task you simply remove the @periodic_task from the codebase, or remove the entry from CELERYBEAT_SCHEDULE. If you are using the Django database scheduler you have to remove the periodic task from the Django Admin interface.

如果要删除周期性任务,只需从代码库中删除@periodic_task,或从CELERYBEAT_SCHEDULE中删除该条目。如果您使用的是Django数据库调度程序,则必须从Django Admin界面中删除定期任务。

PS1: revoke doesn't stop a task that has already been started. It only cancels tasks that haven't been started yet. You can terminate a running task using revoke(task_id, terminate=True). By default this will send the TERM signal to the process, if you want to send another signal (e.g. KILL) use revoke(task_id, terminate=True, signal="KILL").

PS1:撤销不会停止已经启动的任务。它只取消尚未启动的任务。您可以使用revoke终止正在运行的任务(task_id,terminate = True)。默认情况下,如果要发送另一个信号(例如KILL),则会将TERM信号发送到进程,使用revoke(task_id,terminate = True,signal =“KILL”)。

PS2: revoke is a remote control command so it is only supported by the RabbitMQ and Redis broker transports. If you want your task to support cancellation you should do so by storing a cancelled flag in a database and have the task check that flag when it starts:

PS2:revoke是一个远程控制命令,因此只有RabbitMQ和Redis代理传输支持它。如果您希望您的任务支持取消,您应该通过在数据库中存储取消的标志并让任务在启动时检查该标志来执行此操作:

from celery.task import Task

class RevokeableTask(Task):
    """Task that can be revoked.

    Example usage:

        @task(base=RevokeableTask)
        def mytask():
            pass
    """

    def __call__(self, *args, **kwargs):
        if revoke_flag_set_in_db_for(self.request.id):
            return
        super(RevokeableTask, self).__call__(*args, **kwargs)

#2


3  

Just in case this may help someone ... We had the same problem at work, and despites some efforts to find some kind of management command to remove the periodic task, we could not. So here are some pointers.

以防万一这可能对某人有所帮助......我们在工作中遇到了同样的问题,并且无视某些管理命令来取消定期任务,我们做不到。所以这里有一些指示。

You should probably first double-check which scheduler class you're using.

您可能应该首先仔细检查您正在使用的调度程序类。

The default scheduler is celery.beat.PersistentScheduler, which is simply keeping track of the last run times in a local database file (a shelve).

默认调度程序是celery.beat.PersistentScheduler,它只是跟踪本地数据库文件(搁置)中的最后运行时间。

In our case, we were using the djcelery.schedulers.DatabaseScheduler class.

在我们的例子中,我们使用的是djcelery.schedulers.DatabaseScheduler类。

django-celery also ships with a scheduler that stores the schedule in the Django database

django-celery还附带一个调度程序,用于在Django数据库中存储调度

Although the documentation does mention a way to remove the periodic tasks:

虽然文档确实提到了一种删除周期性任务的方法:

Using django-celery‘s scheduler you can add, modify and remove periodic tasks from the Django Admin.

使用django-celery的调度程序,您可以从Django Admin添加,修改和删除定期任务。

We wanted to perform the removal programmatically, or via a (celery/management) command in a shell.

我们希望以编程方式执行删除,或者通过shell中的(celery / management)命令执行删除。

Since we could not find a command line, we used the django/python shell:

由于我们找不到命令行,我们使用了django / python shell:

$ python manage.py shell
>>> from djcelery.models import PeriodicTask
>>> pt = PeriodicTask.objects.get(name='the_task_name')
>>> pt.delete()

I hope this helps!

我希望这有帮助!