A task of Django+Celery is revoked

Posted by AKA Panama Jack on Fri, 15 Oct 2021 04:39:48 +0200

Premise: it is necessary to perform the function of suspending (revoking) a task without affecting the continued execution of other tasks
Find out that celery 3.0 has the revoke function
The official document of celery describes revoke

Here is the test code
Django3.2.8 (this version is not important, but the following two are important)
If the two celery versions don't match, it's very troublesome to use

Django celery the biggest celery supported by this package seems to be celery 3
His Django celery has not been updated for a long time. There is a new one called Django celery base. I'll see it again when I have time

And an important point!!!
After forgetting python, async became a built-in keyword
The celery version is earlier, so it conflicts with the async keyword. If you can't upgrade / downgrade the python version
It is recommended to modify the async keyword in celery (I personally recommend this method. It is too cumbersome to upgrade / downgrade the python version, and there are other things that cannot be used if they are not guaranteed)

  File "/home/lice/.local/lib/python3.8/site-packages/celery/utils/timer2.py", line 19
    from kombu.async.timer import Entry, Timer as Schedule, to_timestamp, logger
SyntaxError: invalid syntax
#We must see here. No matter how many lines of errors he pops up, find the async line and correct it for him

There's more to change
There's more to change
There's more to change
Just start the project several more times. He reports it and changes it once until there is no error (it's bullshit = = |)

Code function description
Publish the celery task, record the task id(task.id) and revoke(task.id) when the task is still running, and destroy it

Model file

Cellery under the project root directory

I use rabbitMQ here

redis, just match it like this

Let's start with tasks and views

from .tasks import *
from Dw_test.celery import app  # Here is your root directory (the setting directory)
from django.http import HttpResponse

from .models import Tasks
from .tasks import *

def ads(request, ls):
    tasks = test_app.apply_async(args=[ls])
    # Remember the tasks, write down his ID and use it later
    # Database record operation
    return HttpResponse(tasks.id)

def dels(req, ls):
    tasks_all = Tasks.objects.get(id=ls)
    app.control.revoke(tasks_all.task_id, terminate=True)
    # If you add it to terminate, it will not be revoked = =. You can also add a signal='SIGKILL ', but I can't measure the difference
    tasks_all.is_delete = True
    # It's all my database record operations
    return HttpResponse(tasks_all.task_id + " is delete")


from __future__ import absolute_import

from time import sleep

from billiard.exceptions import Terminated
from celery import shared_task

# Shared is recommended here_ Task, it can turn your task function into a global shared function. Task cannot. Task must also specify the target cell
@shared_task(throws=(Terminated,))  # This terminated is useful here, as follows
def test_app(x):
    for i in range(x):

Tasks.py (you have to build it manually under the app)

from django.urls import path

from .views import *

urlpatterns = [
    path('task/<int:ls>', ads),
    path('task_del/<int:ls>', dels),

This is urls.py under app (built manually)

If all goes well, start celery
Command: cell - a project name worker -l info
Successfully visible ↓

Let's start the test

The larger the number, the longer the time. The one written earlier can be changed. The returned one is the task id

You can see that it has started running successfully
Now try to terminate this task

If there is no accident, an error will be reported and the task will be successfully cancelled

The solution is to add an exception to the task function (in task.py) I mentioned above


do it again

Successfully stopped

For the pause and start function, you can process the unfinished tasks from the database when starting by saving the unprocessed data in the database


Topics: Python Celery Django