celery——django-celery-beat的celery的配置选项、使用task与shared_task动态创建、取消延时任务以及定时任务

系列文章

django-celery-beat的celery的配置选项、使用task与shared_task动态创建、取消延时任务以及定时任务(celery4版本)


前言

本文中celery版本4.4.7,django-celery-beat版本2.2.0
celery版本5之后存在变化

一、celery的配置选项

首先在项目配置文件配置
settings.py

# 关闭celery的时区感知 
# 开启时celery会以UTC时区作为task的时间判断标准,而我们项目一般都是Asia/shanghai
DJANGO_CELERY_BEAT_TZ_AWARE = False

配置celery配置文件
celery_config.py 下方配置文件以redis作为消息队列

# Celery相关配置
# 设置时区
CELERY_TIMEZONE = "Asia/Shanghai"
# 设置代理人broker
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/11'
# 指定 Backend
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/12'
# celery 的启动工作数量设置
CELERY_WORKER_CONCURRENCY = 10
# 任务预取功能,会尽量多拿 n 个,以保证获取的通讯成本可以压缩。
CELERY_PREFETCH_MULTIPLIER = 20
# 有些情况下可以防止死锁
CELERY_FORCE_EXECV = True
# celery 的 worker 执行多少个任务后进行重启操作
CELERY_WORKER_MAX_TASKS_PER_CHILD = 100
# 禁用所有速度限制,如果网络资源有限,不建议开启。
CELERY_DISABLE_RATE_LIMITS = True

# celery内容等消息的格式设置
CELERY_ACCEPT_CONTENT = ['application/json', ]
# 指定任务序列化方式
CELERY_TASK_SERIALIZER = 'json'
# 指定结果序列化的方式
CELERY_RESULT_SERIALIZER = 'json'

创建celery设置上述配置信息
celery.py

import os
from celery import Celery

# 指定Django默认配置文件模块
# object_name此处为你的项目名(配置文件所在的目录)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'object_name.settings') 
# 创建celery的实例app,要在指定DJANGO_SETTINGS_MODULE环境变量之后

app = Celery('tasks')
# 命名空间 namespace='CELERY'定义所有与celery相关的配置的键名要以'CELERY_'为前缀 
# 前缀可以自己设置,对应的配置文件celery_config.py也要改变
app.config_from_object('object_name.celeryConfig', namespace='CELERY')

# 自动从所有已注册的django app中加载任务
app.autodiscover_tasks()


二、task、shared_task

1. task装饰器

1.1 task任务创建

使用这个装饰器实现的task是需要实例化才能作为celery任务的task来使用
创建一个文件来存放task
celery_task.py

from celery import app # 注意此处引入的是celery的配置选项出配置好的celery.py中创建的app
@app.task
def celery_demo(x, y):
    print("%d + %d = %d" % (x, y, x + y))
    return x + y

1.2 task任务生成

在需要生成celery任务的地方创建即可

from celery_task import celery_demo

def test():
	# 延时任务创建
	celery_demo.delay(args=[1, 2], kwargs={}, countdown=5, eta=datetime)
	# task_id 可以自己设置该唯一标识,不设置时celery会自己设置
	# task_id 用于后续查看任务状态、任务结果、删除任务,设置参数为字符串类型,注意设置时必须保证该值不会重复产生
	# args是用于传递位置参数的
	# kwargs使用传递关键字参数的
	# countdown指定任务在创建后多久触发单位为秒,传递时需要整数类型参数
	# eta指定任务从什么时候开始,需要传递datetime类型参数

from celery.schedules import crontab # 在引入task任务的基础上引入时间对象
	# 定时任务创建
	celery_demo.delay(args=[1, 2], kwargs={}, crontab(minute='*/15')) # 此处*/15为每十五分钟执行一次
	# args是用于传递位置参数的
	# kwargs使用传递关键字参数的
	# crontab 中可加的参数
	# minute 表示分钟,接收整数或者整数列表,范围在0-59,或者字符串表示配置的时间模式
	# hour 表示小时,接收整数或者整数列表,范围在0-23,或者接收字符串表示配置的时间模式
	# day_of_week 表示周几,接收整数或者整数列表,范围在0-6,其中周日是0,周六是6,或者接收字符串表示配置的时间模式
	# day_of_month 表示一个月的第几天,接收整数或者整数列表,范围在1-31,或者接收字符串表示配置的时间模式
	# month_of_year 表示一年的第几个月,接收整数或者整数列表,范围在1-12,或者接收字符串表示配置的时间模式

1.3 获取任务的状态和任务结果

获取对应任务的任务状态、任务结果

from celery.result import AsyncResult
from celery_task import celery_demo

result = AsyncResult(task_id, app=celery_demo) #此处的celery_demo为你要查询的任务所使用的task
# result为任务结果
status = result.status
# status为任务状态,可能为PENDING、 STARTED、 SUCCESS、 FAILURE、 RETRY、 REVOKED以及自定义状态

1.4 取消延时任务

取消延时任务时在worker中进行的

from celery.worker.control import revoke

app.control.revoke(status, task_id) # 此处需要提供要取消的任务实例的任务状态以及task_id

1.5 取消定时任务

取消定时任务需要在beat 和worker中取消

from celery.schedules import crontab
from celery_task import celery_demo
from celery.worker.control import revoke
from celery import beat

scheduler = beat.Scheduler() # 创建scheduler实例
scheduler.cancel(task_id) # 根据唯一标识找到定时任务并取消
scheduler.sync() # 取消之后需要更新beat
result = AsyncResult(task_id, app=celery_demo) # 此处的celery_demo为你要查询的任务所使用的task
revoke(result.status, task_id) # 取消worker中的延时任务

1.6 更新任务

from celery.schedules import crontab
from celery_task import celery_demo
from celery.worker.control import revoke
from celery import beat
# 延时任务与定时任务都能采取取消再创建的方式达成更新的目的

# 延时任务
result = AsyncResult(task_id, app=celery_demo) # 此处的celery_demo为你要查询的任务所使用的task
revoke(result.status, task_id) # 取消worker中的延时任务
celery_demo.apply_async(countdown=new_time, args=[1, 2],task_id=rask_id)

# 定时任务 定时任务运行时是从beat推送给worker所以最好beat 和worker都取消再更新
scheduler = beat.Scheduler() # 创建scheduler实例
scheduler.cancel(task_id) # 根据唯一标识找到定时任务并取消
scheduler.sync() # 取消之后需要更新beat
result = AsyncResult(task_id, app=celery_demo) # 此处的celery_demo为你要查询的任务所使用的task
revoke(result.status, task_id) # 取消worker中的延时任务
celery_demo.delay(args=[1, 2], kwargs={}, crontab(minute='*/15'))

2.shared_task

2.1 shared_task任务创建

使用这个装饰器实现的task是会自动实例化可以直接作为celery任务的task来使用
创建一个文件来存放task
celery_task.py

from celery import shared_task # 注意此处引入的是celery包中的shared_task

@shared_task
def celery_demo(x, y):
    print("%d + %d = %d" % (x, y, x + y))
    return x + y

2.2 shared_task任务生成

在需要使用shared_task任务处调用即可

from celery_task import celery_demo # 先引入使用@shared_task装饰的task任务

# 延时任务创建 
time_seconds = int((instance.end_time - datetime.datetime.now()).seconds)
auto_update_silence.apply_async(countdown=time_seconds, args=[12], task_id="11_task") # task_id要保持唯一
# args(位置参数):要传递给任务函数的位置参数。
# kwargs(关键字参数):要传递给任务函数的关键字参数。
# eta:指定任务的预计执行时间。可以是一个datetime对象或一个时间戳。
# countdown:指定任务从调用apply_async开始到实际执行之间的延迟时间(以秒为单位)。
# expires:指定任务的过期时间。可以是一个datetime对象或一个时间戳。如果任务在过期时间之前没有被执行,将会被丢弃。
# retry:设置任务的重试行为。可以是一个布尔值或一个Retry对象,用于控制任务的重试次数、延迟和回退策略等。
# queue:指定任务所在的队列名称。
# exchange:指定任务所在的交换机名称。
# routing_key:指定任务的路由键。
# priority:指定任务的优先级。
# headers:定义任务的自定义消息头。
# link:指定一个任务完成后要执行的回调任务。
# link_error:指定一个任务出错时要执行的回调任务。


# 定时任务创建
from celery_task import celery_demo # 先引入使用@shared_task装饰的task任务
from django_celery_beat.models import PeriodicTask, IntervalSchedule
schedule, created = IntervalSchedule.objects.get_or_create(
            every=180,
            period=IntervalSchedule.SECONDS, )
# every:这是一个必需的参数,表示任务的执行频率。可以是一个整数或datetime.timedelta对象。例如,every=5表示每5秒执行一次任务,every=datetime.timedelta(minutes=30)表示每30分钟执行一次任务。

# period:可选参数,用于指定时间间隔的单位。可以是以下值之一:'seconds'、'minutes'、'hours'、'days'。默认为'seconds'。

# starts_after:可选参数,表示首次执行任务的延迟时间。可以是一个整数或datetime.timedelta对象。例如,starts_after=10表示任务将在创建后的10秒后开始执行,starts_after=datetime.timedelta(minutes=5)表示任务将在创建后的5分钟后开始执行。默认为0,即立即开始执行任务。

PeriodicTask.objects.create(
    interval=schedule,
    name='asd_hook', # 注意此项属性为唯一标识
    task=celery_demo,
    args=json.dumps([1, 2]),
)
# name:这是一个必需的参数,表示周期性任务的名称。它在系统中唯一标识该任务,并用于检索和操作任务。

# task:这是一个必需的参数,表示要执行的任务函数或任务类的路径。例如,'myapp.tasks.my_task'表示myapp应用中的my_task任务。

# interval:这是一个必需的参数,表示任务的执行频率。它应该是一个IntervalSchedule对象,用于定义任务的时间间隔。

#除了上述必需参数外,PeriodicTask还有一些可选参数:

# enabled:表示任务是否启用。如果设置为False,则任务将不会被调度执行,默认为True。

# args:作为任务函数的位置参数传递给任务的列表。例如,['arg1', 'arg2']表示将arg1和arg2作为位置参数传递给任务函数。

# kwargs:作为任务函数的关键字参数传递给任务的字典。例如,{'key1': 'value1', 'key2': 'value2'}表示将key1和key2作为关键字参数传递给任务函数。

# one_off:表示任务是否只执行一次。如果设置为True,任务将只执行一次,然后停止。默认为False,即任务将周期性地执行。

#headers:作为任务消息头的字典。这些头信息将传递给Celery调度器以控制任务的执行方式。

2.3 获取对应任务的任务状态、任务结果

from celery.result import AsyncResult
from celery_task import celery_demo

result = AsyncResult(task_id, app=celery_demo) #此处的celery_demo为你要查询的任务所使用的task
# result为任务结果
status = result.status
# status为任务状态,可能为PENDING、 STARTED、 SUCCESS、 FAILURE、 RETRY、 REVOKED以及自定义状态

2.4 取消延时任务

from celery.worker.control import revoke

result = AsyncResult(task_id , app=auto_update_silence)
revoke(result.status, task_id)

2.5 取消定时任务

from celery.schedules import crontab
from celery_task import celery_demo
from celery.worker.control import revoke
from celery import beat

scheduler = beat.Scheduler() # 创建scheduler实例
scheduler.cancel(task_id) # 根据唯一标识找到定时任务并取消
scheduler.sync() # 取消之后需要更新beat
result = AsyncResult(task_id, app=celery_demo) # 此处的celery_demo为你要查询的任务所使用的task
revoke(result.status, task_id) # 取消worker中的任务

2.6 更新任务

from celery.schedules import crontab
from celery_task import celery_demo
from celery.worker.control import revoke
from celery import beat
from django_celery_beat.models import PeriodicTask, IntervalSchedule

# 延时任务与定时任务都能采取取消再创建的方式达成更新的目的

# 延时任务
time_seconds = int((instance.end_time - datetime.datetime.now()).seconds)
auto_update_silence.apply_async(countdown=time_seconds, args=[12], task_id="11_task")

# 定时任务 定时任务运行时是从beat推送给worker所以最好beat 和worker都取消再更新
scheduler = beat.Scheduler() # 创建scheduler实例
scheduler.cancel(task_id) # 根据唯一标识找到定时任务并取消
scheduler.sync() # 取消之后需要更新beat
result = AsyncResult(task_id, app=celery_demo) # 此处的celery_demo为你要查询的任务所使用的task
revoke(result.status, task_id) # 取消worker中的任务
schedule, created = IntervalSchedule.objects.get_or_create(
            every=180,
            period=IntervalSchedule.SECONDS, )
PeriodicTask.objects.create(
    interval=schedule,
    name='asd_hook', # 注意此项属性为唯一标识
    task=celery_demo,
    args=json.dumps([1, 2]),
)

补充问题

如果使用@shared_task装饰的task要用于创建延时任务而延时任务正确触发了却没有生效,那么有可能是有引用到上下文的内容那我们需要在延时任务中引入当时任务环境所需要的上下文(此问题需要注意)

# 例如下列的task任务。该任务时基于django创建的,生成延时任务时需要更新数据库中的记录,这个时候我们需要在task重新引入django的上下文
@shared_task 
def auto_update_silence(silence_id):
    """
    屏蔽时间到期时自动更新屏蔽记录
    """
    from django.db import close_old_connections, connection
    from apps.alert.models import Silence
    # 打开数据库连接
    close_old_connections()
    connection.connect()
    try:
        Silence.objects.filter(pk=silence_id).delete()
        celery_log.info(f"silence id:{silence_id} result: success delete silence")
    except Exception as e:
        error_celery_log.error(str(e))
    finally:
        # 关闭数据库连接
        connection.close()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用`django_celery_beat`可以很方便地实现在前端添加定时任务。 首先需要在`settings.py`中配置`django_celery_beat`的数据库信息: ```python INSTALLED_APPS = [ # ... 'django_celery_beat', # ... ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } CELERY_BROKER_URL = 'redis://localhost:6379/0' CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' ``` 在`urls.py`中配置任务添加和删除的路由: ```python from django.urls import path from . import views urlpatterns = [ path('add_task/', views.add_task, name='add_task'), path('delete_task/<int:task_id>/', views.delete_task, name='delete_task'), ] ``` 然后在`views.py`中实现添加和删除任务的方法: ```python from django.shortcuts import render, redirect from django.urls import reverse from django.utils.timezone import localtime from django_celery_beat.models import PeriodicTask, CrontabSchedule from datetime import datetime, timedelta def add_task(request): if request.method == 'POST': task_name = request.POST.get('task_name') task_url = request.POST.get('task_url') task_time = request.POST.get('task_time') task_args = request.POST.get('task_args') task_kwargs = request.POST.get('task_kwargs') task_enabled = True if request.POST.get('task_enabled') == 'on' else False crontab, created = CrontabSchedule.objects.get_or_create( minute=task_time.split(':')[1], hour=task_time.split(':')[0], day_of_week='*', day_of_month='*', month_of_year='*' ) periodic_task = PeriodicTask.objects.create( name=task_name, task='tasks.run_task', args=task_args, kwargs=task_kwargs, crontab=crontab, enabled=task_enabled ) return redirect(reverse('task_list')) return render(request, 'add_task.html') def delete_task(request, task_id): task = PeriodicTask.objects.get(id=task_id) task.delete() return redirect(reverse('task_list')) ``` 在`add_task.html`模板中添加表单用于添加任务: ```html <form method="post" action="{% url 'add_task' %}"> {% csrf_token %} <div class="form-group"> <label for="task_name">Task Name:</label> <input type="text" class="form-control" id="task_name" name="task_name" required> </div> <div class="form-group"> <label for="task_url">Task URL:</label> <input type="text" class="form-control" id="task_url" name="task_url" required> </div> <div class="form-group"> <label for="task_time">Task Time:</label> <input type="time" class="form-control" id="task_time" name="task_time" required> </div> <div class="form-group"> <label for="task_args">Task Args:</label> <input type="text" class="form-control" id="task_args" name="task_args"> </div> <div class="form-group"> <label for="task_kwargs">Task Kwargs:</label> <input type="text" class="form-control" id="task_kwargs" name="task_kwargs"> </div> <div class="form-check"> <input type="checkbox" class="form-check-input" id="task_enabled" name="task_enabled" checked> <label class="form-check-label" for="task_enabled">Enabled</label> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> ``` 最后在`templates`目录下创建`task_list.html`模板用于展示所有定时任务: ```html {% extends 'base.html' %} {% block content %} <h1>Task List</h1> <table class="table table-striped"> <thead> <tr> <th scope="col">#</th> <th scope="col">Name</th> <th scope="col">Task</th> <th scope="col">Args</th> <th scope="col">KWArgs</th> <th scope="col">Time</th> <th scope="col">Enabled</th> <th scope="col">Action</th> </tr> </thead> <tbody> {% for task in tasks %} <tr> <th scope="row">{{ task.id }}</th> <td>{{ task.name }}</td> <td>{{ task.task }}</td> <td>{{ task.args }}</td> <td>{{ task.kwargs }}</td> <td>{{ task.crontab.minute }}:{{ task.crontab.hour }}</td> <td>{% if task.enabled %}Yes{% else %}No{% endif %}</td> <td> <a href="{% url 'delete_task' task.id %}" class="btn btn-danger">Delete</a> </td> </tr> {% endfor %} </tbody> </table> {% endblock %} ``` 在`tasks.py`中实现定时任务的具体操作: ```python from celery import shared_task @shared_task def run_task(url, args=None, kwargs=None): # do something pass ``` 最后在`views.py`中实现展示所有定时任务的方法: ```python from django.shortcuts import render from django_celery_beat.models import PeriodicTask def task_list(request): tasks = PeriodicTask.objects.all() context = { 'tasks': tasks } return render(request, 'task_list.html', context) ``` 这样就可以在前端添加定时任务了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值