Celery定时任务
requirements
celery==3.1.25 异步任务 django-celery==3.2.2 定时任务管理包 redis==2.10.6 django-redis-cache==1.7.1 方便配置Redis缓存
配置
1、工程主APP下的__init__.py文件里添加:
from .celery import app as celery_app __all__ = ['celery_app']
2、工程主APP新建个celery.py文件:
from __future__ import absolute_import import os from celery import Celery # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dts.settings') from django.conf import settings # noqa app = Celery('dts') # Using a string here means the worker will not have to # pickle the object when using Windows. app.config_from_object('django.conf:settings') app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))
启用Celery的定时任务需要设置CELERYBEAT_SCHEDULE 。
说明:
CELERY_RESULT_SERIALIZER = 'json'为了避免错误:# Refusing to deserialize untrusted content of type pickle (application/x-python-serialize)
CELERY_RESULT_BACKEND: 就是把异步任务放到指定地方,方便后续操作。比如后续取出任务判断是否完成
Celery的定时任务都由celery beat来进行调度。celery beat默认按照settings.py之中的时区时间来调度定时任务。
创建定时任务
一种创建定时任务的方式是配置CELERYBEAT_SCHEDULE:
#每30秒调用task.add from datetime import timedelta
from celery.schedules import crontab #为了避免该行报错,在该文件添加绝对包含、from __future__ import absolute_import
CELERYBEAT_SCHEDULE = { 'add-every-30-seconds': { 'task': 'tasks.add', 'schedule': timedelta(seconds=30), 'args': (16, 16) },
'sys_check_unpaid': {
'task': 'dashboard.tasks.mdata_schedule',
'schedule': crontab(minute=0, hour=8, day_of_month=11),
},
}
1 #crontab任务 2 #每周一7:30调用task.add 3 from celery.schedules import crontab 4 5 CELERYBEAT_SCHEDULE = { 6 # Executes every Monday morning at 7:30 A.M 7 'add-every-monday-morning': { 8 'task': 'tasks.add', 9 'schedule': crontab(hour=7, minute=30, day_of_week=1), 10 'args': (16, 16), 11 }, 12 }
使用数据库存储定时任务
使用数据库存储定时任务需要设置CELERYBEAT_SCHEDULE如下:
1 import datetime 2 import json 3 from djcelery import models as celery_models 4 from django.utils import timezone 5 #创建任务 6 def create_task(name, task, task_args, crontab_time): 7 ''' 8 name # 任务名字 9 task # 执行的任务 "myapp.tasks.add" 10 task_args # 任务参数 {"x":1, "Y":1} 11 12 crontab_time # 定时任务时间 格式: 13 { 14 'month_of_year': 9 # 月份 15 'day_of_month': 5 # 日期 16 'hour': 01 # 小时 17 'minute':05 # 分钟 18 } 19 ''' 20 21 # task任务, created是否定时创建 22 task, created = celery_models.PeriodicTask.objects. 23 get_or_create(name=name,task=task) 24 # 获取 crontab 25 crontab = celery_models.CrontabSchedule.objects. 26 filter(**crontab_time).first() 27 if crontab is None: 28 # 如果没有就创建,有的话就继续复用之前的crontab 29 crontab = celery_models.CrontabSchedule.objects. 30 create(**crontab_time) 31 task.crontab = crontab # 设置crontab 32 task.enabled = True # 开启task 33 task.kwargs = json.dumps(task_args) # 传入task参数 34 expiration = timezone.now() + datetime.timedelta(day=1) 35 task.expires = expiration # 设置任务过期时间为现在时间的一天以后 36 task.save() 37 return True 38 #关闭任务 39 def disable_task(name): 40 ''' 41 关闭任务 42 ''' 43 try: 44 task = celery_models.PeriodicTask.objects.get(name=name) 45 task.enabled = False # 设置关闭 46 task.save() 47 return True 48 except celery_models.PeriodicTask.DoesNotExist: 49 return True
启动beat
执行定时任务时, Celery会通过celery beat进程来完成。Celery beat会保持运行, 一旦到了某一定时任务需要执行时, Celery beat便将其加入到queue中. 不像worker进程, Celery beat只需要一个即可。而且为了避免有重复的任务被发送出去,所以Celery beat仅能有一个。
启动:
python manage.py celery beat --loglevel=info
其实还有一种简单的启动方式worker和beat一起启动:
python manage.py celery worker --loglevel=info --beat
定时删除
由于很多任务都是一次执行完就不需要,留在数据库里就是垃圾数据了有没有办法清除。方法肯定有因为django-celery本身就有定时任务功能我们加个任务就解决了。好我们看代码:在django app目录中打开taske.py加入如下代码
from djcelery import models as celery_models from django.utils import timezone @task() def delete(): ''' 删除任务 从models中过滤出过期时间小于现在的时间然后删除 ''' return celery_models.PeriodicTask.objects.filter( expires__lt=timezone.now()).delete()
创建任务脚本里设置了 expires 1天以后过期,这样在filter的时候就能当做条件把过期的任务找到并且删除。