• Django项目中使用celery做异步任务


    异步任务介绍

    在写项目过程中经常会遇到一些耗时的任务, 比如:发送邮件、发送短信等等~。这些操作如果都同步执行耗时长对用户体验不友好,在这种情况下就可以把任务放在后台异步执行
    celery就是用于处理异步任务的框架,celery能完成的功能远不止异步任务,还有一个很常用的功能定时任务

    架构图

    架构.png

    Celery包含如下组件:

    • Celery Beat:任务调度器,Beat进程会读取配置文件的内容,周期性地将配置中到期需要执行的任务发送给任务队列。

    • Celery Worker:执行任务的消费者,通常会在多台服务器运行多个消费者来提高执行效率。

    • Broker:消息代理,或者叫作消息中间件,接受任务生产者发送过来的任务消息,存进队列再按序分发给任务消费方(通常是消息队列或者数据库)。

    • Producer:调用了Celery提供的API、函数或者装饰器而产生任务并交给任务队列处理的都是任务生产者。

    • Result Backend:任务处理完后保存状态信息和结果,以供查询。Celery默认已支持Redis、RabbitMQ、MongoDB、Django ORM、SQLAlchemy等方式。

    Celery 安装

    pip install django-celery celery-with-redis
    

    项目结构

    [vagrant@reboot test_drf]$ tree opsweb/
    opsweb/
    ├── apps
    │   ├── account
    │   │   ├── admin.py
    │   │   ├── apps.py
    │   │   ├── __init__.py
    │   │   ├── migrations
    │   │   ├── models.py
    │   │   ├── __pycache__
    │   │   ├── tasks.py
    │   │   ├── tests.py
    │   │   └── views.py
    ├── celerybeat.pid
    ├── logs
    │   ├── celery
    │   │   ├── beat.log
    │   │   └── celery.log
    ├── manage.py
    ├── opsweb
    │   ├── celery.py
    │   ├── __init__.py
    │   ├── __pycache__
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    

    加载celery app(settings文件中)

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'corsheaders',
        'rest_framework',
        'rest_framework_swagger',
        'account',
        'djcelery' # celery app 很强大
    ]
    

    添加Celery全局配置(settings文件中)

    # Celery
    import djcelery
    djcelery.setup_loader()  # 加载djcelery
    
    CELERY_TIMEZONE = TIME_ZONE
    CELERY_ENABLE_UTC = True
    
    # 允许的格式
    CELERY_ACCEPT_CONTENT = ['pickle', 'json', 'yaml']
    
    BROKER_URL = 'redis://127.0.0.1:6379/0'     # redis作为中间件
    BROKER_TRANSPORT = 'redis'
    CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'     # Backend数据库
    
    # CELERYD_LOG_FILE = BASE_DIR + "/logs/celery/celery.log"         # log路径
    # CELERYBEAT_LOG_FILE = BASE_DIR + "/logs/celery/beat.log"     # beat log路径
    

    同步Celery表到数据库

    python manage.py migrate
    

    创建celery.py文件(与settings同级)

    import os
    import django
    from celery import Celery
    from django.conf import settings
    
    # set the default Django settings module for the 'celery' program.  
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'opsweb.settings')
    django.setup()
    app = Celery('opsweb')
    app.config_from_object('django.conf:settings')
    app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
    @app.task(bind=True)
    def debug_task(self):
        print('Request: {0!r}'.format(self.request))
    

    创建任务文件

    在需要使用异步任务的app中创建tasks.py,写入对应的任务函数,博主喜欢把tasks放在对应的app下,其实放在其他目录下也可以的,看个人习惯

    from opsweb.celery import app
    from celery.schedules import crontab
    import traceback
    from django.contrib.auth.models import User
    import os
    @app.task(name="create_user")
    def useradd(username):
       try:
            print(username)
       except:
            print('fail')
            traceback.print_exc()
    

    触发任务

    在对应的视图中导入tasks中的任务函数调用即可

    from account.tasks import useradd
    # 调用异步任务函数
    useradd.delay('username')
    

    启动Celery

    进入opsweb工程下,启动Celery

    [vagrant@reboot opsweb]$celery -A opsweb worker -B -l info
    或:
    [vagrant@reboot opsweb]$python manage.py celery worker -B -l info
    

    备注:
    本场景用户访问触发任务,流程如下:
    用户页面上点击事件->调用任务/定时计划任务->任务进入redis队列
    ->如果celery启动则依次执行任务->如果celery没启动,则会存到redis

    队列里,一旦启动就依次执行

    启动Django

    [vagrant@reboot opsweb]$python manage.py runserver 0:8000
    

    测试

    页面上触发了异步任务就会在celery日志里看到任务信息,我这里只是写了简单的任务例子

    [2018-09-01 23:56:59,704: WARNING/Worker-2] hello
    [2018-09-01 23:56:59,707: INFO/MainProcess] Received task: create_user[c9724e23-b9ba-44fc-b195-6b1153d2c161]
    [2018-09-01 23:56:59,708: INFO/MainProcess] Task create_user[f3b3e644-b8aa-4679-8a42-0efc2574abf6] succeeded in 0.0038937819999773637s: None
    

    计划任务 - djcelery

    djcelery app提供了定时任务的功能,注册并同步到数据库之后,会生产五个表,结构如下:

    MariaDB [test002]> show tables
        -> ;
    +---------------------------+
    | Tables_in_test002         |
    +---------------------------+
    ...
    | djcelery_crontabschedule  |
    | djcelery_intervalschedule |
    | djcelery_periodictask     |
    | djcelery_periodictasks    |
    | djcelery_taskstate        |
    | djcelery_workerstate      |
    +---------------------------+
    

    在django后台可以看到注册的表
    定时任务.png

    每个任务可以接受参数

    job.png

    定时任务函数

    from opsweb.celery import app
    @app.task(name="create_user"  )
    def create_user(*args,**kwargs): # 分别接收后台传入的列表和字典参数
        print (args,kwargs)
    

    启动Celery beat

    [vagrant@reboot opsweb]$ python manage.py celery beat # 启动定时任务
    

    Celery会通过celery beat进程来完成. Celerybeat会保持运行, 一旦到了某一定期任务需要执行时, Celery beat便将其加入到queue中

    supervisor管理Celery任务

    配置如下

    • 主动触发任务
    celery_worker.conf
    [program:celery_worker]
    # 进入工作目录
    directory=/vagrant/test_drf/opsweb
    # 执行celery指令
    command=python manage.py celery worker -B -l info
    autorestart=true
    loglevel=info
    redirect_stderr=true
    stdout_logfile=/var/log/supervisor/celery_worker.log
    
    • 定时任务触发
    celery_beat.conf 同上, 区别如下:
    [program:celery_beat]
    command=python manage.py celery beat
    stdout_logfile=/var/log/supervisor/celery_beat.log
    

    一些不错的文章
    http://www.cnblogs.com/znicy/p/5626040.html Django中使用celery,非常经典
    https://www.cnblogs.com/huangxiaoxue/p/7266253.html 基于celery开发的平台,非常棒
    http://python.jobbole.com/81953/ 刘天斯大神 经典案例
    http://www.imooc.com/article/16164 慕课网老师博客
    http://blog.csdn.net/michael_lbs/article/details/74923367 python+django+djcelery
    http://blog.csdn.net/lizhihua0925/article/details/53842110 model api

    http://www.jianshu.com/p/7085dcc70d0e 挺好
    http://blog.csdn.net/crb912/article/details/78344659 很详细

  • 相关阅读:
    还是解决不了滚动条的缩放问题
    全屏问题的解决
    eclipse自带内存监视及回收插件Hidden Heap Status
    Apache2.2“the requested operation has failed”解决方法
    开源软件推介(三)
    Warning: mysql_connect() [function.mysqlconnect]: [2002] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试 (trying to connect via tcp://localhost:3306)
    pdf阅读器新需求
    学Linq to sql(十):分层构架的例子(四)
    告别ASP.NET操作EXCEL的烦恼(总结篇)——放到首页奢侈下
    Linq to sql(十):分层构架的例子(二)
  • 原文地址:https://www.cnblogs.com/guigujun/p/9574702.html
Copyright © 2020-2023  润新知