flask celery异步任务实践

最近在写接口自动化平台的时候,一个功能是批量执行测试用例,即对一个测试集操作。
测试集的执行时间可能会较长,所以想做成一个异步任务。python 实现异步任务最常见的工具是celery,此次使用flask和celery完成了功能,将实践结果进行记录。

celery

Celery是Python开发的分布式任务调度模块,可以执行异步任务和定时任务。
详细内容可以查看官网的文档

安装
pip install celery
消息中间件

Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。
celery支持的消息中间件很多,包括消息队列、关系型数据库和非关系型数据库。最常见的有RabbitMQ和Redis。RabbitMQ是官方推荐使用的,相比较于redis的一个好处是消息可以持久保存。
我使用的是RabbitMQ作为消息中间件。celery作为生产者将任务保存在消息队列中,之后由消费者者将队列中的任务进行消费。

任务执行单元

Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。
此处的worker其实就是一个消费者,从消息队列中获取消息并进行执行。
worker是需要单独启动的,并不是跟随flask一起启动的。
分布式的意思就是可以启动多个worker,像多个工人并发的进行工作。

任务结果存储

Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis等。
由于在业务上我执行任务的功能有保存对应的执行结果在业务数据库表中,此处没有用到结果存储。

Flask-Celery-Helper

github地址
为了更加方便的flask进行集成,使用了flask-celery-helper这个库。
下面的例子也是基于这个库编写的。
使用这个库的原因除了更加方便的使用配置信息,更重要的是可以在celery中使用flask 上下文对象。

安装
pip install Flask-Celery-Helper

异步任务实现

以下只显示了celery相关的代码
config.py

from app.config.setting import BaseConfig


class DevelopmentSecure(BaseConfig):
    """
    开发环境安全性配置
    """
    CELERY_BROKER_URL = 'amqp://admin:admin2000@www.xxxxx.red:8083/my_vhost'

CELERY_BROKER_URL 是消息中间件RbbitMq的连接信息
init.py

from flask_celery import Celery
celery = Celery()

实例化celery对象

app.py

from app.libs.init import mongo, socket_io, celery

def create_app(register_all=True, environment='production'):
    app = LinFlask(__name__, static_folder='./assets')
    app.config['ENV'] = environment
    env = app.config.get('ENV')
    if env == 'production':
        app.config.from_object('app.config.setting.ProductionConfig')
        app.config.from_object('app.config.secure.ProductionSecure')
    elif env == 'development':
        app.config.from_object('app.config.setting.DevelopmentConfig')
        app.config.from_object('app.config.secure.DevelopmentSecure')
    app.config.from_object('app.config.log')
    if register_all:
        register_blueprints(app)
        from app.models.user import User
        Lin(app, user_model=User)
        register_before_request(app)
        register_after_request(app)
        apply_cors(app)
        # 创建所有表格
        create_tables(app)
        mongo.init_app(app)
        celery.init_app(app)
        socket_io.init_app(app, cors_allowed_origins='*')

    return app

创建app对象 celery.init_app(app) 的作用是将celery注册到app上
starter.py

from app.app import create_app

app = create_app(environment='development')

from app.libs.init import celery

celery.conf.update(imports='app.libs.tasks')

if __name__ == '__main__':
    app.run(debug=True)

starter.py是项目的启动文件。
由于是通过这个文件的celery来启动worker,此处celery.conf.update需要引入celery任务的路径。
在这个文件的目录下启动worker

celery -A starter.celery worker -l info --pool=solo

tasks.py

from app.libs.init import celery
from app.models.project import Project
from celery.utils import log

sys.path.append('../../')


celery.conf.update(imports='app.libs.tasks')


@celery.task
def execute_test(pid):
    # 初始化工程进度
    project = Project.query.filter_by(id=pid, delete_time=None).first_or_404()
    project.update_progress(progress=0, running=True)
    try:
        project.batch()
        log.logger.info('任务执行完成')
    finally:
        time.sleep(3)
        project.update_progress(progress=0, running=False)
    return True

execute_test 是需要异步执行的任务

task.py

@task_api.route('/<pid>', methods=['GET'])
def execute_project(pid):
    project = Project.query.filter_by(id=pid, delete_time=None).first_or_404()
    project.is_running()
    from app.libs.tasks import execute_test
    execute_test.delay(pid)
    return Success(msg='启动成功')

execute_test.delay(pid) 进行celery任务调用

存在的问题

在celery的任务中无法使用socketio(flask-socketio)
功能需求是在任务执行完毕后向所有连接的客户端广播是哪个任务执行完成了。
查询了一些资料,应该是不支持在celery中直接使用socketio进行websocket消息发送。
只能曲线救国了,在celery中调用自己服务的api,在被调用的api中进行socketio的emit。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值