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

news2024/11/17 7:49:53

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 email
    email_data = {
        'subject': 'Hello from Flask',
        'to': email,
        'body': '来自python--flask框架延时发送的邮件内容~'
    }
    if request.form['submit'] == 'Send':
        # send right away
        send_async_email.delay(email_data)
        print('here!--')
        flash('Sending email to {0}'.format(email))
    else:
        # send in one minute
        send_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 Celery


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 "发送成功"


# 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 email
    email_data = {
        'subject': 'Hello from Flask',
        'to': email,
        'body': '来自python--flask框架延时发送的邮件内容~'
    }
    if request.form['submit'] == 'Send':
        # send right away
        send_async_email.delay(email_data)
        print('here!--')
        flash('Sending email to {0}'.format(email))
    else:
        # send in one minute
        send_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 elements
            div = $('<div class="progress"><div></div><div>0%</div><div>...</div><div>&nbsp;</div></div><hr>');
            $('#progress').append(div);

            // create a progress bar
            var 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 UI
                percent = 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 seconds
                    setTimeout(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.coloradmin.cn/o/1040210.html

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

相关文章

1688-阿里巴巴批发网(获取优惠券信息)

item_get_app-获取1688app上原数据 为了进行电商平台 的API开发&#xff0c;首先我们需要做下面几件事情。 1&#xff09;开发者注册一个账号 2&#xff09;然后为每个1688 应用注册一个应用程序键&#xff08;App Key) 。 3&#xff09;下载1688 API的SDK并掌握基本的API基…

惠普P1108激光打印机报错光束探测错误检修

在使用打印机的过程中&#xff0c;有时候会遇到光束探测错误的问题&#xff0c;导致打印机无法正常工作。这个问题可能是由多种原因引起的&#xff0c;包括硬件故障、驱动程序错误、操作系统问题等。在这里&#xff0c;我将为您提供一些解决光束探测错误的方法。 故障描述&…

SpringBoot 学习(七)Swagger

7. Swagger 7.1 简介 便于前后端集成联调RestFul Api 文档在线生成工具 > Api 文档与 Api 定义同步更新直接运行&#xff0c;在线测试 Api 接口 7.2 springboot 集成 swagger (1) 导入依赖 <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger…

清华用7个ChatGPT模拟《狼人杀》,结果出乎意料!

为了验证大语言模型的沟通、规划、反思等拟人化能力&#xff0c;清华研究团队发布了一篇名为“探索大语言模型在交流游戏中的应用&#xff1a;《狼人杀》实验”的研究论文。 结果显示&#xff0c;通过ChatGPT&#xff08;GPT -turbo-0301&#xff09;构建的7个玩家&#xff0c…

【高云FPGA系列教程(11):MultiButton按键驱动模块移植】

文章目录 1. MultiButton简介2. MultiButton代码获取3. MultiButton移植4. 测试与运行本文是高云FPGA系列教程的第11篇文章。 1. MultiButton简介 MultiButton, 一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构…

nssm部署jar包

nssm部署jar包 1、软件下载 官方传送门 csdn下载地址 2、安装服务 F: cd F:\服务启动目录 set JAVA_HOMEF:\Program Files\Java\jdk1.8.0_181 set CLASSPATH.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOMe%\lib\tools.jar; set Path%JAVA_HOME%\bin; java -Dfile.encodingutf-8 -…

解决Vue设置图片的动态src不生效的问题

一、问题描述 在vue项目中&#xff0c;想要动态设置img的src时&#xff0c;此时发现图片会加载失败。在Vue代码中是这样写的&#xff1a; 在Vue的data中是这样写的&#xff1a; 我的图片在根目录下的static里面&#xff1a; 但是在页面上这个图片却无法加载出来。 二、解决方案…

使用原生html<table>构造复杂table表

<table border data-sort"sortDisabled" align"center" class"table"><tbody><tr class"textarea1"><td rowspan"1" colspan"2" class"background-gray"><label>日期<…

更新andriod studio版本,项目编译报could not find org.junit.jupiter:junit-jupiter

原本使用Android Studio 版本是4.1.1&#xff0c;现更新为 点击build -》 build bundle -》build apk&#xff0c;项目报 Could not determine the dependencies of task :app:compileDebugUnitTestJavaWithJavac. > Could not resolve all task dependencies for configur…

前脚收费,后脚道歉?Unity收费新规引众怒,Epic承诺虚幻引擎永久免费

&#xfeff;当你还在纠结开发游戏用Unity引擎还是UE虚幻引擎的时候&#xff0c;Unity已经给游戏开发领域重重一拳。 &#xfeff;Unity作为一款全球范围内广泛使用的游戏引擎&#xff0c;因其价格亲民且灵活而备受众多开发者的青睐。然而在9月12日&#xff0c;Unity突然宣布计…

分析大疆官网根据ip自动跳转到指定域名

如果cookie存在region且有效&#xff0c;跳转到指定域名&#xff0c; 如果cookie存在region且无效&#xff0c;跳转到默认域名&#xff0c; 如果禁用cookie或者cookie中没有region&#xff0c;根据ip自动判断所在地区&#xff0c;跳转到指定域名 1、浏览器地址栏输入dji.com&am…

2018-2022年盟浪 ESG数据

2018-2022年盟浪 ESG数据 1、时间&#xff1a;2018-2022年 2、指标&#xff1a;证券代码、证券简称、盟浪ESG评级、省份、城市、所属证监会行业名称[交易日期] 最新收盘日[行业级别] 大类行业、所属证监会行业代码[交易日期] 最新收盘日[行业级别] 大类行业 3、范围&#xf…

图像练习-计算平行线距离opencv(03)

原图 //对输入图像进行细化 cv::Mat ThinLine(const cv::Mat& matsrc, const int& iterations) {//CvSize size cvGetSize(src);cv::Mat dst matsrc.clone();//拷贝一个数组给另一个数组int _iwidth dst.cols;int _iheight dst.rows;int n 0, i 0, j 0;for (n …

【每日一题】658. 找到 K 个最接近的元素

658. 找到 K 个最接近的元素 - 力扣&#xff08;LeetCode&#xff09; 给定一个 排序好 的数组 arr &#xff0c;两个整数 k 和 x &#xff0c;从数组中找到最靠近 x&#xff08;两数之差最小&#xff09;的 k 个数。返回的结果必须要是按升序排好的。 整数 a 比整数 b 更接近 …

抖音SEO矩阵系统源码开发搭建

1. 确定需求和功能&#xff1a;明确系统的主要目标和需要实现的功能&#xff0c;包括关键词研究、短视频制作、外链建设、数据分析、账号设置优化等方面。 2. 设计系统架构&#xff1a;根据需求和功能确定系统的架构&#xff0c;包括前端、后端、数据库等部分的设计&#xff0…

计算机组成原理之硬件的内部结构,拆开单独的硬件,查看硬件组成部分的结构和功能。

大家好&#xff0c;欢迎阅读《计算机组成原理》的系列文章&#xff0c;本系列文章主要教内容是从零学习计算机组成原理&#xff0c;内容通俗易懂&#xff0c;大家好好学习吧&#xff01;&#xff01;&#xff01; 更多的优质内容&#xff0c;请点击以下链接查看哦~~ ↓ ↓ ↓ …

【加载数据--自定义自己的Dataset类】

【加载数据自定义自己的Dataset类】 1 加载数据2 数据转换3 自定义Dataset类4 划分训练集和测试集5 提取一批次数据并绘制样例图 假设有四种天气图片数据全部存放与一个文件夹中&#xff0c;如下图所示&#xff1a; ├─dataset2 │ cloudy1.jpg │ cloudy10.jpg │ …

使用matlab产生二维动态曲线视频文件具体举例

使用matlab产生二维动态曲线视频文件举例 在进行有些函数变化过程时候&#xff0c;需要用到直观的动态显示&#xff0c;本博文将举例说明利用Matlab编程进行二维动态曲线的生成视频文件。 一、问题描述 利用matlab编程实现 y 1 s i n ( t ) , y 2 c o s ( t ) , y 3 s i …

JAVA_多线程的实现方式

线程的状态 方式一&#xff1a; public class Thread1 extends Thread {Overridepublic void run() {synchronized (this) {for (int i 0; i < 100; i) {System.out.println(getName() "" i);}}} } Thread1 thread1 new Thread1(); thread1.start(); 方式二…

用flex实现grid布局

1. css代码 .flexColumn(columns, gutterSize) {display: flex;flex-flow: row wrap;margin: calc(gutterSize / -2);> div {flex: 0 0 calc(100% / columns);padding: calc(gutterSize / 2);box-sizing: border-box;} }2.用法 .grid-show-item3 {width: 100%;display: fl…