Celery结合flask完成异步任务与定时任务

Celery 常用于 web 异步任务、定时任务等。
使用 redis 作为 Celery的「消息代理 / 消息中间件」。
这里通过Flask-Mail使用qq邮箱延时发送邮件作为示例

pip install celery
pip install redis
pip install Flask-Mail

1、使用flask发送邮件

使用 Flask-Mail 发送邮件需要进行一下配置,其中QQ邮箱授权码的获取方式如下所述:

app = Flask(__name__)
app.config['SECRET_KEY'] = 'top-secret!'# Flask-Mail configuration
app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 465
# 启用/禁用传输安全层加密
app.config['MAIL_USE_TLS'] = False
# 启用/禁用安全套接字层加密
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = '我的QQ邮箱@qq.com'
app.config['MAIL_PASSWORD'] = '我的QQ邮箱授权码'
app.config['MAIL_DEFAULT_SENDER'] = '我的QQ邮箱@qq.com'# Celery configuration
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'# Initialize extensions
mail = Mail(app)@app.route("/send_mail")
def index11():# sender:发件人    recipients:收件人msg = Message('Hello', sender = app.config['MAIL_DEFAULT_SENDER'], recipients = ['目标邮箱@qq.com'])msg.body = "来自python--flask框架发送的邮件内容~"mail.send(msg)#发送Message类对象的内容return "发送成功"

点进qq邮箱,在设置里面点击账号,向下滚动开启pop3服务获取授权码。

2、延时发送邮件

定义celery任务,与flask基本一样 只是前面多了修饰符@celery.task

@celery.task
def send_async_email(email_data):"""Background task to send an email with Flask-Mail."""msg = Message(email_data['subject'],sender=app.config['MAIL_DEFAULT_SENDER'],recipients=[email_data['to']])msg.body = email_data['body']with app.app_context():mail.send(msg)     
@app.route('/', methods=['GET', 'POST'])
def index():if request.method == 'GET':return render_template('index.html', email=session.get('email', ''))email = request.form['email']session['email'] = email# send the emailemail_data = {'subject': 'Hello from Flask','to': email,'body': '来自python--flask框架延时发送的邮件内容~'}if request.form['submit'] == 'Send':# send right awaysend_async_email.delay(email_data)print('here!--')flash('Sending email to {0}'.format(email))else:# send in one minutesend_async_email.apply_async(args=[email_data], countdown=60)flash('An email will be sent to {0} in one minute'.format(email))return redirect(url_for('index'))

3、生成带有状态信息进度条的异步任务


# bind为True,会传入self给被装饰的方法
@celery.task(bind=True)
def long_task(self):"""带有进度条以及状态报告的 异步任务"""verb = ['正在', '准备', '目前', '处于', '进行']adjective = ['全速', '努力', '默默地', '认真', '快速']noun = ['打开', '启动', '修复', '加载', '检查']message = ''total = random.randint(10, 50)  # 随机取10~50的一个随机数for i in range(total):selectnow = random.random()print(selectnow)# 拼接上面三个lsit  随机的生成一些状态描述if not message or selectnow < 0.25:message = '{0} {1} {2}...'.format(random.choice(verb),random.choice(adjective),random.choice(noun))# 更新Celery任务状态self.update_state(state='PROGRESS',meta={'current': i, 'total': total,'status': message})time.sleep(1)# 返回字典return {'current': 100, 'total': 100, 'status': '任务完成!','result': 42}@app.route('/longtask', methods=['POST'])
def longtask():task = long_task.apply_async()return jsonify({}), 202, {'Location': url_for('taskstatus', task_id=task.id)}@app.route('/status/<task_id>')
def taskstatus(task_id):task = long_task.AsyncResult(task_id)# print(task.state)if task.state == 'PENDING':# PENDING的时候  如果一直PENDING可能是celery没开启response = {'state': task.state,'current': 0,'total': 1,'status': 'Pending...'}elif task.state != 'FAILURE':# 加载的时候response = {'state': task.state,'current': task.info.get('current', 0),'total': task.info.get('total', 1),'status': task.info.get('status', '')}if 'result' in task.info:response['result'] = task.info['result']else:# 报错时候的输出response = {'state': task.state,'current': 1,'total': 1,'status': str(task.info),  # this is the exception raised}return jsonify(response)

4、完整代码

文件结构

--- current--- templates--- index.html--- asyn_001.py
这个是asyn_001.py
import os
import random
import time
from flask import Flask, request, render_template, session, flash, redirect, \url_for, jsonify
from flask_mail import Mail, Message
from celery import Celeryapp = Flask(__name__)
app.config['SECRET_KEY'] = 'top-secret!'# Flask-Mail configuration
app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 465
# 启用/禁用传输安全层加密
app.config['MAIL_USE_TLS'] = False
# 启用/禁用安全套接字层加密
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = '我的QQ邮箱@qq.com'
app.config['MAIL_PASSWORD'] = '我的QQ邮箱授权码'
app.config['MAIL_DEFAULT_SENDER'] = '我的QQ邮箱@qq.com'# Celery configuration
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'# Initialize extensions
mail = Mail(app)@app.route("/send_mail")
def index11():# sender:发件人    recipients:收件人msg = Message('Hello', sender = app.config['MAIL_DEFAULT_SENDER'], recipients = ['目标邮箱@qq.com'])msg.body = "来自python--flask框架发送的邮件内容~"mail.send(msg)#发送Message类对象的内容return "发送成功"# Initialize Celery
celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)@celery.task
def send_async_email(email_data):"""Background task to send an email with Flask-Mail."""msg = Message(email_data['subject'],sender=app.config['MAIL_DEFAULT_SENDER'],recipients=[email_data['to']])msg.body = email_data['body']with app.app_context():mail.send(msg)@app.route('/', methods=['GET', 'POST'])
def index():if request.method == 'GET':return render_template('index.html', email=session.get('email', ''))email = request.form['email']session['email'] = email# send the emailemail_data = {'subject': 'Hello from Flask','to': email,'body': '来自python--flask框架延时发送的邮件内容~'}if request.form['submit'] == 'Send':# send right awaysend_async_email.delay(email_data)print('here!--')flash('Sending email to {0}'.format(email))else:# send in one minutesend_async_email.apply_async(args=[email_data], countdown=60)flash('An email will be sent to {0} in one minute'.format(email))return redirect(url_for('index'))# bind为True,会传入self给被装饰的方法
@celery.task(bind=True)
def long_task(self):"""带有进度条以及状态报告的 异步任务"""verb = ['正在', '准备', '目前', '处于', '进行']adjective = ['全速', '努力', '默默地', '认真', '快速']noun = ['打开', '启动', '修复', '加载', '检查']message = ''total = random.randint(10, 50)  # 随机取10~50的一个随机数for i in range(total):selectnow = random.random()print(selectnow)# 拼接上面三个lsit  随机的生成一些状态描述if not message or selectnow < 0.25:message = '{0} {1} {2}...'.format(random.choice(verb),random.choice(adjective),random.choice(noun))# 更新Celery任务状态self.update_state(state='PROGRESS',meta={'current': i, 'total': total,'status': message})time.sleep(1)# 返回字典return {'current': 100, 'total': 100, 'status': '任务完成!','result': 42}@app.route('/longtask', methods=['POST'])
def longtask():task = long_task.apply_async()return jsonify({}), 202, {'Location': url_for('taskstatus', task_id=task.id)}@app.route('/status/<task_id>')
def taskstatus(task_id):task = long_task.AsyncResult(task_id)# print(task.state)if task.state == 'PENDING':# PENDING的时候  如果一直PENDING可能是celery没开启response = {'state': task.state,'current': 0,'total': 1,'status': 'Pending...'}elif task.state != 'FAILURE':# 加载的时候response = {'state': task.state,'current': task.info.get('current', 0),'total': task.info.get('total', 1),'status': task.info.get('status', '')}if 'result' in task.info:response['result'] = task.info['result']else:# 报错时候的输出response = {'state': task.state,'current': 1,'total': 1,'status': str(task.info),  # this is the exception raised}return jsonify(response)if __name__ == '__main__':app.run(debug=True)
这个是index.html
<html><head><title>Flask + Celery 示例</title><style>.progress {width: 100%;text-align: center;}</style></head><body><h1>Flask + Celery 示例</h1><h2>Example 1: 发送异步邮件</h2>{% for message in get_flashed_messages() %}<p style="color: red;">{{ message }}</p>{% endfor %}<form method="POST"><p>Send test email to: <input type="text" name="email" value="{{ email }}"></p><input type="submit" name="submit" value="Send"><input type="submit" name="submit" value="Send in 1 minute"></form><hr><h2>Example 2: 生成进度条以及状态报告</h2><!--<button οnclick="start_long_task();">Start Long Calculation</button><br><br>--><button id="start-bg-job">Start Long Calculation</button><br><br><div id="progress"></div><script src="//cdnjs.cloudflare.com/ajax/libs/nanobar/0.2.1/nanobar.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script><script>function start_long_task() {// add task status elementsdiv = $('<div class="progress"><div></div><div>0%</div><div>...</div><div>&nbsp;</div></div><hr>');$('#progress').append(div);// create a progress barvar nanobar = new Nanobar({bg: '#44f',target: div[0].childNodes[0]});// send ajax POST request to start background job$.ajax({type: 'POST',url: '/longtask',success: function(data, status, request) {status_url = request.getResponseHeader('Location');console.log("status_url", status_url,"nanobar", nanobar, "div[0]", div[0])console.log("data", data)update_progress(status_url, nanobar, div[0]);},error: function() {alert('Unexpected error');}});}function update_progress(status_url, nanobar, status_div) {// send GET request to status URL$.getJSON(status_url, function(data) {// update UIpercent = parseInt(data['current'] * 100 / data['total']);nanobar.go(percent);$(status_div.childNodes[1]).text(percent + '%');$(status_div.childNodes[2]).text(data['status']);if (data['state'] != 'PENDING' && data['state'] != 'PROGRESS') {if ('result' in data) {// show result$(status_div.childNodes[3]).text('Result: ' + data['result']);}else {// something unexpected happened$(status_div.childNodes[3]).text('Result: ' + data['state']);}}else {// rerun in 2 secondssetTimeout(function() {update_progress(status_url, nanobar, status_div);}, 2000);}});}$(function() {$('#start-bg-job').click(start_long_task);});</script></body>
</html>

5、启动任务

终端cd到current文件夹所在目录
在这里插入图片描述
启动asyn_001程序,即可观察到异步任务的执行。

参考1 Celery实现异步任务和定时任务的简单示例
参考2 Using Celery with Flask

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

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

相关文章

数据分析三剑客之一:Numpy详解及实战

1 NumPy介绍 NumPy 软件包是Python生态系统中数据分析、机器学习和科学计算的主力军。它极大地简化了向量和矩阵的操作处理。Python的一些主要软件包&#xff08;如 scikit-learn、SciPy、pandas 和 tensorflow&#xff09;都以 NumPy 作为其架构的基础部分。除了能对数值数据…

适配器模式 结构性模式之五

1.概念 适配器模式是一种结构型的软件设计模式&#xff0c;也称包装模式&#xff0c;即将相对复杂的功能&#xff08;可能用到多个类&#xff09;封装起来&#xff0c;提供一个使用者想要的接口&#xff0c;使用者只需要调用接口&#xff0c;不需要知道接口里封装的内容是如何实…

热门敏捷开发管理工具

敏捷管理研发工具可以协助团队更好地进行敏捷开发和管理。以下是几种流行的敏捷管理研发工具&#xff1a; Leangoo&#xff1a;Leangoo领歌一款永久免费的专业敏捷研发管理工具&#xff0c;它覆盖了敏捷项目研发全流程&#xff0c;包括小型团队敏捷开发&#xff0c;规模化敏捷…

Linux基本指令(一)

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; C&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大…

对负采样(negative sampling)的一些理解

负采样&#xff08;negative sampling&#xff09;通常用于解决在训练神经网络模型时计算softmax的分母过大、难以计算的问题。但在LightGCN模型论文的BPR LOSS中&#xff0c;负采样的概念可能与传统的softmax分母问题不完全一样。 在LightGCN模型中&#xff0c;不同于传统的协…

AR智能眼镜:提升现场服务技能、效率与盈利能力的利器(一)

随着技术的不断进步&#xff0c;现场服务组织正朝着远程支持转变&#xff0c;用以解决技能差距和生产力问题&#xff0c;提高员工培训和操作效率&#xff0c;同时为企业提高利润率&#xff0c;创造竞争优势。 本文将探讨增强现实&#xff08;AR&#xff09;、辅助现实&#xf…

使用Apache HttpClient爬取网页内容的详细步骤解析与案例示例

Apache HttpClient是一个功能强大的开源HTTP客户端库&#xff0c;本文将详细介绍如何使用Apache HttpClient来爬取网页内容的步骤&#xff0c;并提供三个详细的案例示例&#xff0c;帮助读者更好地理解和应用。 一、导入Apache HttpClient库 在项目的pom.xml文件中添加依赖&a…

【李沐深度学习笔记】损失函数

课程地址和说明 损失函数p2 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 损失函数 损失函数是用来衡量预测值 y ^ \hat{y} y^​或 y ′ y y′与真实值 y y y的差别&#xff0c;下面给出常见的损失函数类型&am…

MySQL数据库记录的删除操作与特殊字符

在数据库管理中,除了添加和修改记录之外,删除操作也是一个重要的方面。同时特殊字符序列的处理也是必不可少的一步。 本文将深入探讨如何在MySQL数据库中进行表记录的删除操作,以及如何处理特殊字符序列。将使用《三国志》游戏数据作为示例来进行解释。 文章目录 表记录的…

科技资讯|AirPods Pro基于定位控制的自适应音频功能

在接受 TechCrunch 媒体采访时&#xff0c;苹果高管 Ron Huang 和 Eric Treski 谈到了关于 AirPods Pro 自适应音频&#xff08;Adaptive Audio&#xff09;功能的轶事&#xff0c;曾考虑基于 GPS 信号来控制自适应音频级别。 Treski 表示在探索自适应音频功能初期&#xff0…

uniapp 实现下拉筛选框 二次开发定制

前言 最近又收到了一个需求&#xff0c;需要在uniapp 小程序上做一个下拉筛选框&#xff0c;然后找了一下插件市场&#xff0c;确实有找到&#xff0c;但不过他不支持搜索&#xff0c;于是乎&#xff0c;我就自动动手&#xff0c;进行了二开定制&#xff0c;站在巨人的肩膀上&…

什么是GraphQL?它与传统的REST API有什么不同?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是GraphQL&#xff1f;⭐ 与传统的REST API 的不同⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣…

UnityAPI的学习——Application类

Application类不含实例属性和实例方法&#xff0c;在脚本通过直接调用Application类的静态属性和静态方法来控制程序的运行时数据&#xff0c;如场景的管理、数据的加载等。   Application类静态属性   在Application类中&#xff0c;涉及的静态属性主要有dataPath和loaded…

ESP32设备通信-两个ESP32设备之间HTTP通信

两个ESP32设备之间HTTP通信 文章目录 两个ESP32设备之间HTTP通信1、应用介绍2、软件准备3、硬件准备4、代码实现4.1 ESP32服务器节点代码4.2 ESP32客户端节点代码在本文中,我们将介绍如何在没有任何物理路由器或互联网连接的情况下使用 Wi-Fi 在两个 ESP32 开发板之间执行无线…

7.网络原理之TCP_IP(上)

文章目录 1.网络基础1.1认识IP地址1.2子网掩码1.3认识MAC地址1.4一跳一跳的网络数据传输1.5总结IP地址和MAC地址1.6网络设备及相关技术1.6.1集线器&#xff1a;转发所有端口1.6.2交换机&#xff1a;MAC地址转换表转发对应端口1.6.3主机&#xff1a;网络分层从上到下封装1.6.4主…

【新版】系统架构设计师 - 软件架构的演化与维护

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 软件架构的演化与维护考点摘要软件架构演化和定义面向对象软件架构演化对象演化消息演化复合片段演化约束演化 软件架构演化方式静态演化动态演化 软件架构演化原则软件架构演化评估方法大型网站架…

【Codeforces】 CF917D Stranger Trees

题目链接 CF方向 Luogu方向 题目解法 一个显然的转化是&#xff1a;恰好 k k k 条边不好求&#xff0c;所以把 恰好 转化成 至少&#xff0c;然后进行二项式反演 令 f i f_i fi​ 为恰好 k k k 条边 . . . ... ...&#xff0c; g i g_i gi​ 为至少 k k k 条边 . . . …

Ubuntu 20.04二进制部署Nightingale v6.1.0和Prometheus

sudo lsb_release -r可以看到操作系统版本是20.04&#xff0c;sudo uname -r可以看到内核版本是5.5.19。 sudo apt-get update进行更新镜像源。 完成之后&#xff0c;如下图&#xff1a; sudo apt-get upgrade -y更新软件。 选择NO&#xff0c;按下Enter。 完成如下&…

自定义注解实现Redis分布式锁、手动控制事务和根据异常名字或内容限流的三合一的功能

自定义注解实现Redis分布式锁、手动控制事务和根据异常名字或内容限流的三合一的功能 文章目录 [toc] 1.依赖2.Redisson配置2.1单机模式配置2.2主从模式2.3集群模式2.4哨兵模式 3.实现3.1 RedisConfig3.2 自定义注解IdempotentManualCtrlTransLimiterAnno3.3自定义切面Idempote…

问题记录 springboot 事务方法中使用this调用其它方法

原因: 因为代理对象中调用了原始对象的toString()方法,所以两个不同的对象打印出的引用是相同的