需求:django中定时给用户推送消息、或者定时更新数据库的某个字段内容
本文介绍如何在django中使用celery和定时任务,以及配置celery日志文件
一、安装
pip install django-celery
pip install django-redis
pip install celery
pip install redis
django-crontab 定时任务
安装完成
注意版本之间的兼容性,之前就踩过很多坑,运行时发现报错,就是因为版本之间不兼容导致,本例中使用的版本:
二、文件结构
我的项目名称叫hrms,首先在项目根目录下新建celery_tasks包,作为celery服务的根目录。
config.py是celery的配置文件;
main.py是celery服务启动的入口文件;
mail包是发邮件的任务目录
sms包是发短信的任务目录
update_hruser包是定时更新简历的任务目录
三、config.py文件
from celery.schedules import crontab
import logging.config
指定任务队列的位置
BROKER_URL = "redis://127.0.0.1/0"
指定消息执行结果的位置
CELERY_RESULT_BACKEND = "redis://127.0.0.1/0"
一定要写下面这句,指定时区,否则celery默认使用utc时间,设置的hour会延迟8小时执行
CELERY_TIMEZONE = 'Asia/Shanghai'
# 这里博主列出了三个最典型的定时任务,更多用法自行百度crontab语法
CELERYBEAT_SCHEDULE = {
# 定时任务一: 每5分钟执行一次任务(refresh1)
'refresh1': {
"task": "celery_tasks.update_hruser.tasks.refresh",
"schedule": crontab(hour='*/5'),
"args": (),
},
# 定时任务二: 每天的凌晨2:00,执行任务(refresh2)
'refresh2': {
"task": "celery_tasks.update_hruser.tasks.refresh",
'schedule': crontab(minute=0, hour=2),
"args": ()
},
# 定时任务三:每个月的1号的6:00启动,执行任务(refresh3)
'refresh3': {
"task": "celery_tasks.update_hruser.tasks.refresh",
'schedule': crontab(hour=6, minute=0, day_of_month='1'),
"args": ()
},
}
LOG_CONFIG = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '%(asctime)s \"%(pathname)s:%(module)s:%(funcName)s:%(lineno)d\" [%(levelname)s]- %(message)s'
}
},
'handlers': {
'celery': {
'level': 'INFO',
'formatter': 'simple',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'celery.log',
'encoding': 'utf-8',
},
},
'loggers': {
'celery': {
'handlers': ['celery'],
'level': 'INFO',
'propagate': True,
}
}
}
logging.config.dictConfig(LOG_CONFIG)
四、main.py文件
from celery import Celery
import os
# 为celery使用django配置文件进行设置,注意main.py和settings.py的相对位置关系
if not os.getenv('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = 'hrms.settings.settings'
# 创建celery对象,并起别名
celery_app = Celery('hrms')
#从配置文件加载配置
celery_app.config_from_object('celery_tasks.config')
#此时用定时任务来触发celery任务,因此不需要再注册celery任务,后来我发现同时存在定时任务触发异步任务和手动触发异步任务时,
定时任务触发的异步任务必须要注册到这里才能生效,而且任务函数都需要@celery_app.task()装饰器注册,不知道是我代码的问题还是celery的问题。
celery_app.autodiscover_tasks(['celery_tasks.mail', 'celery_tasks.sms'])
(新版本celery的autodiscover_tasks函数好像不需要参数)
五、tasks.py文件
from django.db import transaction
from django.utils import timezone
from recruit.models import HrUser, Skill
from utils.file_util import FileUtil
from utils.hrnlp import Extract
from celery_tasks.main import celery_app
from celery.utils.log import get_task_logger
logger = get_task_logger('celery')
# 此定时任务是定时更新简历的skill_tags字段
@celery_app.task()
def refresh():
ctime = timezone.localtime()
stime = ctime + timezone.timedelta(days=-1)
skill_is_changed = Skill.objects.filter(update_time__gt=stime)
if skill_is_changed:
queryset = HrUser.objects.all()
with transaction.atomic():
for q in queryset:
value = FileUtil.get_data_from_txt(q.alltxt)
tags = Extract.find_tags(value.lower())
q.skill_tags = tags
q.save()
# 日志的使用
logger.info('Refresh task start and refresh success')
else:
logger.info('Refresh task start but nothing has changed')
六、启动定时任务
切换到项目根目录下执行:
python manage.py runserver 启动django
celery worker -A celery_tasks.main -l debug -f logs/celery.log 启动celery worker 服务
celery beat -A celery_tasks.main -l info 检查定时任务,并启动定时任务丢给worker执行。