首先在项目配置文件配置
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是需要实例化才能作为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
在需要生成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,或者接收字符串表示配置的时间模式
获取对应任务的任务状态、任务结果
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以及自定义状态
取消延时任务时在worker中进行的
from celery.worker.control import revoke
app.control.revoke(status, task_id) # 此处需要提供要取消的任务实例的任务状态以及task_id
取消定时任务需要在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中的延时任务
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'))
使用这个装饰器实现的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
在需要使用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=[1,2], 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调度器以控制任务的执行方式。
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以及自定义状态
from celery.worker.control import revoke
result = AsyncResult(task_id , app=auto_update_silence)
revoke(result.status, task_id)
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中的延时任务
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=[1,2], 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()