Django使用Celery实现异步发送邮件
作者:CodeDevMaster 发布时间:2022-11-04 17:50:47
前言
在Django使用Celery异步发送邮件的过程中,遇到Celery日志提示任务已接收,但实际上任务并没有执行,解决后特此记录。
使用版本如下:
Django版本:4.1.4
Celery版本:5.2.7
邮箱配置
进入邮箱,找到POP3/SMTP/IMAP项,开启POP3/SMTP服务,添加客户端授权码
Django项目发送邮件
配置邮件服务器
发送邮件时需要配置好SMTP服务器的连接信息。在settings.py
中配置邮件服务器信息
# 配置邮件发送
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# 对应邮箱服务器地址
EMAIL_HOST = 'smtp.163.com'
# 端口
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = 'admin@163.com'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'YS22JE123PAZJ2N'
#收件人看到的发件人
EMAIL_FROM = 'admin<admin@163.com>'
Django发送邮件模块
Django自带了发送邮件的模块django.core.mail
,可以方便地使用它来发送电子邮件
send_mail方法描述:
send_mail(subject, message, from_email, recipient_list, html_message=None)
subject 主题 邮件标题
message 普通邮件正文,普通字符串
from_email 发件人
recipient_list 收件人列表
html_message 多媒体邮件正文,可以是html字符串
基本使用示例:
from django.core.mail import send_mail
subject = 'Subject' # 主题
message = 'Message' # 正文
from_email = 'noreply@example.com' # 发件人地址
recipient_list = ['recipient1@example.com', 'recipient2@example.com'] # 收件人地址列表
send_mail(subject, message, from_email, recipient_list)
Celery
发送邮箱邮件是耗时操作,所以需要异步发送邮件,使用Celery实现异步任务。
概述
Celery是一个基于Python的分布式任务队列,它可以轻松地处理大量的并发任务。Celery支持多种消息传输协议,如AMQP、Redis等,同时也支持多种后端存储系统,如RabbitMQ、Redis等。通过使用Celery,我们可以将一些耗时的任务放到异步的任务队列中,从而提高Web应用的响应速度和性能。
Celery的工作原理非常简单。首先定义一个任务(Task),然后将这个任务加入到任务队列中。Celery Worker会从任务队列中取出任务并执行,完成后将结果返回给调用方。可以根据需要对任务进行优先级排序、设定任务超时时间等。
除了作为任务队列之外,Celery还可以用来实现周期性任务调度,比如定时清理缓存、备份数据库等。Celery提供了丰富的API和插件,可以轻松地完成各种复杂的任务处理需求。
官网:https://docs.celeryq.dev/en/stable/index.html
GitHub:https://github.com/celery/celery
工作模式
默认是进程池方式,进程数以当前机器的CPU核数为参考,每个CPU开四个进程。
指定进程数:
# proj:celery实例对象文件
celery worker -A proj --concurrency=4
改变进程池方式为协程方式:
# 安装eventlet模块
pip install eventlet
# 启用Eventlet,指定协程数目
celery worker -A proj --concurrency=1000 -P eventlet -c 1000
安装Celery
安装Celery
pip install -U Celery
Celery的基本使用
创建config.py配置文件
# 设置代理人broker,使用redis的5号库
broker_url = "redis://127.0.0.1/5"
# 设置结果存储,使用redis的6号库
result_backend = "redis://127.0.0.1/6"
# 任务超时限制
task_time_limit = 10 * 60
# 时区
celery_timezone = 'Asia/Shanghai'
创建Celery实例并加载配置
创建celery_tasks 包,然后创建main.py文件,实现创建Celery实例并加载配置
import os
from celery import Celery
from celery_tasks import config
# 为celery使用django配置文件进行设置,识别和加载django的配置文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '项目名.settings')
# 创建celery实例,参数是celery名称,需保证唯一
celery_app = Celery('celery_tasks')
# 加载celery配置,设置broker队列
celery_app.config_from_object(config)
定义任务
在包celery_tasks
下创建任务包test_task
,并在该包下创建tasks.py
文件,用于定义任务
from celery_tasks.main import celery_app
# bind:保证task对象会作为第一个参数自动传入
# name:异步任务别名
# retry_backoff:异常自动重试的时间间隔 第n次(retry_backoff×2^(n-1))s
# max_retries:异常自动重试次数的上限
@celery_app.task(bind=True, name='test_task', retry_backoff=3)
def celerTest(self, number):
try:
print("执行{}号任务".format(number))
except Exception as e:
# 有异常自动重试三次
raise self.retry(exc=e, max_retries=3)
在celery_tasks.main.py文件种进行任务注册
import os
from celery import Celery
# 让celery使用django配置文件,即加载当前工程的配置文件
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")
# 创建celery实例,参数是celery名称,需保证唯一
celery_app = Celery('demo_celery')
# 加载celery配置,指定配置文件路径,即可设置broker队列
celery_app.config_from_object('celery_tasks.config')
# 自动注册celery任务,列表元素是任务包路径
celery_app.autodiscover_tasks(['celery_tasks.test_task'])
启动Celery服务
# -A 对应的应用程序, 其参数是项目中Celery实例的位置
# worker 要启动的worker
# -l 日志等级,如info等级
celery -A celery_tasks.main worker -l info
(demo) D:\WorkSpace\Python\demo\demo>celery -A celery_tasks.main worker -l info
-------------- celery@Coding v5.2.7 (dawn-chorus)
--- ***** -----
-- ******* ---- Windows-10-10.0.22000-SP0 2023-01-16 23:25:49
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: demo_celery:0x1fdba863d00
- ** ---------- .> transport: redis://127.0.0.1:6379/8
- ** ---------- .> results: redis://127.0.0.1/9
- *** --- * --- .> concurrency: 12 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. test_task
[2023-01-16 23:25:49,701: INFO/MainProcess] Connected to redis://127.0.0.1:6379/8
[2023-01-16 23:25:49,703: INFO/MainProcess] mingle: searching for neighbors
[2023-01-16 23:25:50,095: INFO/SpawnPoolWorker-1] child process 49036 calling self.run()
[2023-01-16 23:25:50,114: INFO/SpawnPoolWorker-2] child process 43196 calling self.run()
[2023-01-16 23:25:50,136: INFO/SpawnPoolWorker-3] child process 1284 calling self.run()
[2023-01-16 23:25:50,154: INFO/SpawnPoolWorker-4] child process 49708 calling self.run()
[2023-01-16 23:25:50,183: INFO/SpawnPoolWorker-5] child process 49704 calling self.run()
[2023-01-16 23:25:50,208: INFO/SpawnPoolWorker-6] child process 20884 calling self.run()
[2023-01-16 23:25:50,221: INFO/SpawnPoolWorker-7] child process 17840 calling self.run()
[2023-01-16 23:25:50,242: INFO/SpawnPoolWorker-8] child process 56040 calling self.run()
[2023-01-16 23:25:50,275: INFO/SpawnPoolWorker-9] child process 45968 calling self.run()
[2023-01-16 23:25:50,291: INFO/SpawnPoolWorker-10] child process 44888 calling self.run()
[2023-01-16 23:25:50,313: INFO/SpawnPoolWorker-11] child process 8848 calling self.run()
[2023-01-16 23:25:50,318: INFO/SpawnPoolWorker-12] child process 11020 calling self.run()
[2023-01-16 23:25:50,727: INFO/MainProcess] mingle: all alone
[2023-01-16 23:25:50,740: WARNING/MainProcess] D:\Development\Python\env\demo\lib\site-packages\celery\fixups\django.py:203: UserWarning: Using settings.DEBUG leads to a memory
leak, never use this setting in production environments!
warnings.warn('''Using settings.DEBUG leads to a memory
[2023-01-16 23:25:50,741: INFO/MainProcess] celery@Coding ready.
[2023-01-16 23:25:51,332: INFO/SpawnPoolWorker-13] child process 4580 calling self.run()
[2023-01-16 23:25:51,341: INFO/SpawnPoolWorker-14] child process 44956 calling self.run()
[2023-01-16 23:25:51,453: INFO/SpawnPoolWorker-15] child process 46100 calling self.run()
[2023-01-16 23:25:51,466: INFO/SpawnPoolWorker-16] child process 46872 calling self.run()
[2023-01-16 23:25:52,797: INFO/SpawnPoolWorker-17] child process 2716 calling self.run()
[2023-01-16 23:25:52,800: INFO/SpawnPoolWorker-18] child process 49488 calling self.run()
[2023-01-16 23:25:52,807: INFO/SpawnPoolWorker-19] child process 3912 calling self.run()
[2023-01-16 23:25:53,608: INFO/SpawnPoolWorker-20] child process 40624 calling self.run()
提交任务
from celery_tasks.test_task.tasks import celerTest
if __name__ == '__main__':
for i in range(1,10):
celerTest.delay(i)
异常
提交任务 Celery控制台日志出现示任务已接收,但并没有执行
INFO/MainProcess] Task send_email[f301b786-af40-4283-a4d6-4a97ae05658f] received
INFO/MainProcess] Task send_email[5997d896-fdb2-4220-92fe-7027291df56d] received
原因:
celery对windows支持不好,需添加组件eventlet 指定协程
解决办法
pip install eventlet
celery -A celery_tasks.main worker -l info -P eventlet -c 10
执行1号任务
执行2号任务
执行3号任务
执行4号任务
执行5号任务
执行6号任务
执行7号任务
执行8号任务
执行9号任务
INFO/MainProcess] Task send_email[01457c6c-4571-4b1e-b09c-39df49d50162] received
WARNING/MainProcess] 执行1号任务
INFO/MainProcess] Task send_email[01457c6c-4571-4b1e-b09c-39df49d50162] succeeded in 1.2969999999913853s: None
Celery发送邮件
创建config.py配置文件
# 设置代理人broker,使用redis的5号库
broker_url = "redis://127.0.0.1/5"
# 设置结果存储,使用redis的6号库
result_backend = "redis://127.0.0.1/6"
# 任务超时限制
celery_task_time_limit = 10 * 60
# 时区
celery_timezone = 'Asia/Shanghai'
创建Celery实例并加载配置
创建定义Celery包:celery_tasks
,然后创建main.py文件,实现创建Celery实例并加载配置
import os
from celery import Celery
from celery_tasks import config
# 为celery使用django配置文件进行设置,识别和加载django的配置文件
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '项目名称.settings')
# 创建celery实例,参数是celery名称,需保证唯一
celery_app = Celery('celery_tasks')
# 加载celery配置,设置broker队列
celery_app.config_from_object(config, namespace='CELERY')
# celery_app.config_from_object('celery_tasks.config')
# 自动注册celery任务,列表元素是任务包路径
celery_app.autodiscover_tasks(['celery_tasks.email'])
定义发送邮件任务
在包celery_tasks
下创建任务包email_task
,并在该包下创建tasks.py
文件,用于定义任务
from django.conf import settings
from django.core.mail import send_mail
from celery_tasks.main import celery_app
# bind:保证task对象会作为第一个参数自动传入
# name:异步任务别名
# retry_backoff:异常自动重试的时间间隔 第n次(retry_backoff×2^(n-1))s
# max_retries:异常自动重试次数的上限
@celery_app.task(bind=True, name='send_email', retry_backoff=3)
def sendEmail(self, to_email, verify_url):
subject = "邮箱验证"
html_message = '<p>尊敬的用户您好!</p>' \
'<p>您的邮箱为:%s 。请点击此链接激活您的邮箱:</p>' \
'<p><a href="%s" rel="external nofollow" >%s<a></p>' % (to_email, verify_url, verify_url)
try:
send_mail(subject, "", settings.EMAIL_FROM, [to_email], html_message=html_message)
except Exception as e:
# 有异常自动重试三次
raise self.retry(exc=e, max_retries=3)
启动Celery
在使用Celery时,需要启动worker进程来处理异步任务。可以使用以下命令来启动worker进程:
celery -A celery_tasks.main worker -l info -P eventlet -c 10
调用发送邮件异步任务
定义请求地址
from django.urls import re_path
from . import views
urlpatterns = [
re_path(r'^send/$', views.SendView.as_view(), name='send'),
]
定义视图,并发送邮件
class SendView(View):
def get(self, request):
for i in range(1, 2):
# 异步发送验证邮件
verify_url = 'https://www.admin.com'
email = 'admin@qq.com'
res = sendEmail.delay(email, verify_url)
print(res)
return http.JsonResponse({"msg": "OK"})
来源:https://juejin.cn/post/7224514121206382649
猜你喜欢
- 对模型中的字段进行验证Django模型中的内置字段验证是所有Django字段预定义的默认验证。每个字段都带有来自Django验证器的内置验证
- 喜欢Gucci的优雅吗?或者痴迷美国普普艺术?谷歌中国最近改版的谷歌个性化首页iGoogle集中了近1500个主题,包括近120多位全球顶级
- 前言在实际开发中, 有不少的场景需要使用到模糊查询, MongoDB shell 模糊查询很简单:db.collection.find({&
- 在 python2 中,如果想要自定义评价标准的话,可以这么做def cmp(a, b): # 如果逻辑上认为 a < b ,返回 -
- 环境:python3 + unittest + requestsExcel管理测试用例,HTMLTestRunner生成测试报告测试完成后邮
- 前面讲解了使用纯numpy实现数值微分和误差反向传播法的手写数字识别,这两种网络都是使用全连接层的结构。全连接层存在什么问题呢?那就是数据的
- <!-- #include file="conn.asp" -->
- GitPython 是一个用于操作 Git 版本库的 python 包,它提供了一系列的对象模型(库 - Repo、树 - Tree、提交
- 本文实例讲述了python实现支持目录FTP上传下载文件的方法。分享给大家供大家参考。具体如下:该程序支持ftp上传下载文件和目录、适用于w
- 一、PL/SQL出现的目的 结构化查询语言(Structured Query Language,简称SQL)是用来访问关系型数据库一种通用语
- MySQL服务器有几个影响其操作的参数(变量)。如果缺省的参数值不合适,可以将其修改为对服务器运行环境更合适的值。例如,如果您有大量的内存,
- 本文适用场景:想用Tkinter开发界面程序并屏幕居中,但没找到相应的API。这两天玩了玩Tkinter,感觉不错,就是屏幕居中这个问题在网
- 前言: 这篇文章主要介绍RMAN的常用方法,其中包含了作者一些自己的经验,里面的实验也基本全在WIN 2K和ORACLE 8.1.6环境下测
- 本文实例为大家分享了python rsync服务器之间文件夹同步的具体代码,供大家参考,具体内容如下About rsync配置两
- 前言当我们需要对列表(list)、元组(tuple)、字典(dictionary)和集合(set)的元素进行遍历时,其实Python内部都是
- 改编自详解利用OpenCV提取图像中的矩形区域(PPT屏幕等) 原文是c++版,我改成了python版,供大家参考学习。主要思想:边缘检测—
- PHP策略模式(Strategy Pattern)策略模式是一种行为设计模式,它允许在运行时选择算法行为的方法。该模式定义了一组算法,将每个
- 很久没写blog,太忙了。没什么时间写复杂的东西,重新把颜色渐变效果写一遍。关于颜色的效果一般就两个,颜色梯度变化和样式的颜色渐变,前者在i
- 前言最近想做个小玩意,需要在mac端实现屏幕截图,搜了下网上中文资源都比较老旧,于是查了下,发现有些好用的Python库已经支持Mac 以及
- icon可以用多个软件制作,也可以通过一些网站把普通图片转换为.ico文件,但通常存在的问题是图片本该透明的地方经转换后变为了黑色或者白色,