Django使用Celery异步发送邮件

news2024/12/23 9:06:27

Django使用Celery异步发送邮件

  • 前言
  • 邮箱配置
  • Django项目发送邮件
    • 配置邮件服务器
    • Django发送邮件模块
  • Celery
    • 概述
    • 工作模式
    • 安装Celery
  • Celery的基本使用
    • 创建config.py配置文件
    • 创建Celery实例并加载配置
    • 定义任务
    • 启动Celery服务
    • 提交任务
    • 异常
  • Celery发送邮件
    • 创建config.py配置文件
    • 创建Celery实例并加载配置
    • 定义发送邮件任务
    • 启动Celery
    • 调用发送邮件异步任务

前言

在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">%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"})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/446976.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习 day05(多元线性回归,向量化,及向量化高效的原理)

1. 单个特征&#xff08;变量&#xff09;的线性回归模型 房子的价格仅由房子的大小决定&#xff0c;如图&#xff1a; 2. 多个特征&#xff08;变量&#xff09;的线性回归模型 房子的价格由房子的大小&#xff0c;房子有多少个卧室&#xff0c;房子有几层&#xff0c;房子…

2023年,逆势拿到大厂Offer,我怎么做?|原创

关于面试&#xff0c;做一些经验分享。 过年时候默默给自己定下了3个目标。第一个就是2023要换一份喜欢的工作。没想到在4月就提前实现了这个目标。 是一个我很看好的大厂&#xff0c;期待的岗位、看好的方向&#xff0c;薪资涨幅也比较给力。最近这段时间没空发文章&#xff0…

MySql中,join 语句怎么优化?

既然每次从驱动表取数据比较耗时&#xff0c;那我们每次从驱动表取一批数据放到内存中&#xff0c;然后对这一批数据进行匹配操作。这批数据匹配完毕&#xff0c;再从驱动表中取一批数据放到内存中&#xff0c;直到驱动表的数据全都匹配完毕 批量取数据能减少很多IO操作&#…

二十三、高级网络技术及应用——BFD解析

文章目录 前言一、BFD 简介1、概述&#xff1a;2、作用&#xff1a; 二、静态路由调用 BFD1、配置静态 BFD2、配置动态 BFD 三、OSPF联动BFD四、BFD 单臂回声&#xff08;one arm echo&#xff09; 前言 BFD&#xff1a;Bidirectional Forwarding Detection&#xff0c;双向转…

奇舞周刊第490期:WebAssembly 多语言/宿主环境中的使用

记得点击文章末尾的“ 阅读原文 ”查看哟~ 下面先一起看下本期周刊 摘要 吧~ 奇舞精选 ■ ■ ■ WebAssembly 多语言/宿主环境中的使用 WebAssembly (WASM) 的一个优势就是能够支持将不同语言编译成 WASM 代码&#xff0c;然后在不同的宿主环境中运行。这样就可以在不同的宿主环…

【WSN定位】基于多通信半径和跳距加权优化的Dvhop定位算法【Matlab代码#15】

文章目录 1. 原始Dvhop定位算法2. 多通信半径3. 加权跳距4. 部分代码展示5. 仿真结果展示6. 资源获取 1. 原始Dvhop定位算法 可参考Dvhop定位算法 2. 多通信半径 设网络通信半径为 R R R&#xff0c;将锚节点与邻居节点间分为 m m m级&#xff0c;网络中各信标节点与其邻居节…

Nuxt3用nginx部署到二级目录

有的时候我们需要把我们写的Nuxt3项目部署到域名的二级目录&#xff0c;例如&#xff1a;https://abc.xx.com/abc/目录下。主要就是用nginx进行配置代理转发来实现的&#xff0c;这样可以实现我们同一个域名下可以部署多个Nuxt3独立的项目&#xff0c;只不过端口不同。使用ngin…

Node【Global全局对象】之【Buffer】

文章目录 &#x1f31f;前言&#x1f31f;Buffer&#x1f31f;Buffer介绍&#x1f31f;Buffer对象&#xff1a;类似于数组&#xff0c;其元素是16进制的两位数。&#x1f31f;什么时候用Buffer&#x1f31f;Buffer的转换&#x1f31f;Buffer使用&#x1f31f;创建Buffer&#x…

uniapp 来电显示悬浮窗插件(支持锁屏来电) Ba-CallerID

简介&#xff08;下载地址&#xff09; Ba-CallerID 是一款来电显示悬浮窗插件插件。 支持显示、隐藏支持锁屏来电显示支持自定义位置显示&#xff08;上、中、下&#xff09;支持拖动&#xff08;这版不支持&#xff0c;需要的话可以加&#xff09;支持申请、判断悬浮窗权限…

3个实用的文字转语音方法,让你时刻保持信息更新!

现在&#xff0c;我们生活节奏加快&#xff0c;信息量也越来越大&#xff0c;有时候想了解新闻却又不想眼睛再去盯着手机屏幕了&#xff0c;这时候文字转语音工具就可以帮助我们实现听新闻的需求。如果你还不了解文字如何转换成语音&#xff0c;别担心&#xff0c;今天我将向大…

JavaSE注解和反射

注解分类和说明点 注解&#xff1a;可对程序做解释可被其他程序读取 元注解&#xff1a;Target&#xff1a;表明注解的使用范围&#xff0c;Retention&#xff1a;表示要在什么级别保存注解信息&#xff0c;Document&#xff0c;Inherited 自定义注解&#xff1a;interface …

P1027 [NOIP2001 提高组] Car 的旅行路线

题目描述 又到暑假了&#xff0c;住在城市 A 的 Car 想和朋友一起去城市旅游。 她知道每个城市都有 44 个飞机场&#xff0c;分别位于一个矩形的 44 个顶点上&#xff0c;同一个城市中两个机场之间有一条笔直的高速铁路&#xff0c;第 &#xfffd;i 个城市中高速铁路了的单位…

【let变量声明以及声明特性】

let变量声明以及声明特性 1 let变量声明2 let声明特性3 let经典案例实践 1 let变量声明 <script>// 声明变量let a;let b,c,d;let e 100;let f 521, g iloveyou, h [];</script>2 let声明特性 1> 变量不能重复声明2> 块级作用域、全局作用域、函数作用域…

4.5 函数最佳逼近

学习目标&#xff1a; 要学习函数最佳逼近&#xff0c;我可能会采取以下几个步骤&#xff1a; 学习基本的数学知识和工具&#xff1a;函数最佳逼近涉及到线性代数、实变函数、泛函分析等多个领域的知识&#xff0c;因此我需要先学习这些基础知识和工具&#xff0c;例如矩阵和向…

论文各子结构的实现

本文将简明介绍人工智能论文各子结构的实现方法&#xff0c;重点指出了各部分实现时的要点&#xff0c;帮助读者高效地完成论文的写作。 1. 标题 论文标题的确定必须遵循明确而有吸引力的原则。论文的题目需要准确反映自己论文的研究内容和创新点&#xff0c;同时还必须具有吸…

嵌入式软件中常见的 8 种数据结构详解

目录 第一&#xff1a;数组 1、数组的应用 第二&#xff1a;链表 1、链表操作 2、链表的应用 第三&#xff1a;堆栈 1、堆栈操作 2、堆栈的应用 第四&#xff1a;队列 1、队列操作 2、队列的应用 第五&#xff1a;哈希表 1、哈希函数 2、哈希表的应用 第六&#…

chatgpt智能提效职场办公-ppt怎么设置背景图片

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 在 Microsoft PowerPoint 中&#xff0c;可以按照以下步骤设置背景图片&#xff1a; 打开 PowerPoint 文档并进入“设计”选项卡。 在…

HJY系列数字式交流电压继电器(数显型) 导轨安装 约瑟JOSEF

1 用途 HJY系列数字式交流电压继电器为瞬时动作特性&#xff0c;用于发电机&#xff0c;变压器&#xff0c;输电线路的继电保护装 置中作为过压或欠压的闭锁启动元件。 安装结构 导轨安装9&#xff0c;导轨安装E两种结构方式&#xff0c;具体尺寸请参考外型尺寸图。特点 (1). …

1小时学会CSS-下

今天给大家分享的内容包含CSS 盒子模型&#xff0c;CSS 标准布局&#xff0c; CSS 浮动布局 &#xff0c; 并以案列进行详细说明。 一、CSS 盒子模型 CSS 将所有元素都当成盒子&#xff0c;CSS布局其实就是如何堆放盒子。 组成: content(内容)—>padding(内边距)—>bor…

【python视图1】networkx操作图

一、说明 数据可视化需要显示种种数据&#xff0c;matplotlib负责曲线类画图&#xff0c;然而类似于图论的操作用什么方法。这里用networkx程序包完成。本文专门介绍这种程序包的用法。 二、生成图&#xff08;Creating a graph&#xff09; 2.1 创建一个没有节点和边的空图。…