django使用celery动态添加定时任务,发送邮件
celery文档:https://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#beat-custom-schedulers
django-celery-beat文档 : https://pypi.org/project/django-celery-beat/
依赖及版本:
django==3.2.4
celery==5.2.0
django-celery==3.3.1
django-celery-beat==2.3.0
django-celery-results==2.4.0
python-crontab==2.6.0
redis==4.3.0
eventlet==0.33.1
项目结构:
-- myproject
-- myproject
-- __init__.py
-- asgi.py
-- settings.py
-- urls.py
-- wsgi.py
-- celery_tasks
-- __init__.py
-- celery.py
-- config.py
-- tasks.py
通用配置:
settings.py
#邮件相关配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
#邮件服务配置文件 SSL认证,验证
EMAIL_USE_SSL = True
#邮箱服务
EMAIL_HOST = 'smtp.exmail.qq.com'
#端口号
EMAIL_PORT = 465
#账号
EMAIL_HOST_USER = 'xxxxxx.com.cn'
#授权秘钥
EMAIL_HOST_PASSWORD = 'xxxxxxxxx'
#发件人
EMAIL_FROM = EMAIL_HOST_USER
celery.py
import os, django
from datetime import timedelta
from celery import Celery
from celery.schedules import crontab
# 把celery和django进行组合,识别和加载django的配置文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'HRS.settings')
django.setup()
# 创建celery实例
app = Celery('celery_tasks')
# 指定celery消息队列的配置
app.config_from_object("celery_tasks.config")
# 从所有的django-app中加载任务
app.autodiscover_tasks(['celery_tasks'])
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False
config.py
# 设置结果存储
result_backend = 'redis://xxx.xx.x.xx:xxxx/x'
# 设置代理人broker
broker_url = 'redis://xxx.xx.x.xx:xxxx/x'
timezone = 'Asia/Shanghai' # 时区
CELERY_TASK_TIME_LIMIT = 30 * 60 # 任务超时限制
tasks.py
# 使用django内置函数发送邮件
from django.core.mail import send_mail
# 导入django的settings
from django.conf import settings
from celery_tasks.celery import app
@app.task
def send_mail_task(email, username):
"""
使用django内置函数发送邮件
"""
subject = "test"
message = "test send mail"
sender = settings.EMAIL_FROM
recipient = [email]
html_message = "<h1>%s 666</h1>" % username
send_mail(subject, message, sender, recipient, html_message=html_message)
1.非动态添加定时任务(初始化celery时添加)
在celery.py中添加如下代码
# 设置定时任务
app.conf.beat_schedule = {
'send-report': {
'task': 'celery_tasks.tasks.send_mail_task', # 要启动的任务
# 'schedule': crontab(hour=10, minute=1), # 每天早上10点01分发送邮件
'schedule': timedelta(seconds=30),
'args': ("xxxxxx.com.cn", "aaaaaaa") # 传入需要的参数
}
}
然后启动beat:
celery -A celery_tasks beat -l info
再启动worker:
celery -A celery_tasks worker -l info -P eventlet
会看到beat和worker都有相应的执行记录即表示成功
ps:worker启动后看task里是否有你注册好的任务,没有就是路径没配对或app.autodiscover_tasks()里没添加任务所在路径
2.动态添加定时任务
settings.py
app中添加如下
INSTALLED_APPS = [
...
'django_celery_beat',
]
config.py
新增如下:
# celery beat配置
CELERY_ENABLE_UTC = False
DJANGO_CELERY_BEAT_TZ_AWARE = False
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
views.py
在你视图需要按一定条件添加定时任务的业务代码中添加如下:
class testview(APIView):
"""
这是用来测试的接口
"""
def get(self, r):
import json, pytz
from django_celery_beat.models import PeriodicTask, IntervalSchedule
# 每10秒执行一次,其余类型的定时任务详见文档不赘述
schedule, created = IntervalSchedule.objects.get_or_create(
every=10,
period=IntervalSchedule.SECONDS,)
PeriodicTask.objects.create(
interval=schedule,
name='send mail3',
task='celery_tasks.tasks.send_mail_task',
args=json.dumps(["xxxxxxxx.com.cn", "aaaaaaa"]),
)
return JsonResponse({"message":"ok"})
启动django项目,生成beat相关数据库:
执行:python manage.py migrate
然后启动worker:
celery -A celery_tasks worker -l info -P eventlet
启动beat:
celery -A celery_tasks beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
然后调用上述get接口,注册定时任务,beat的日志会打印数据库发生变化,到时间后会执行相应操作。
ps:
PeriodicTask.objects.create()创建的任务,name是唯一索引,所以起名字要唯一,保证每次调用都是不同的名字,名字相同,创建时会报错,注意捕获错误防止程序崩溃。