目录:

一、celery简介

二、基本概念

三、使用 Celery 实现异步任务的步骤

四、使用 Celery 实现定时任务的步骤

五、celery定时任务简单使用

 

一、celery:

1、定义:一个强大的分布式任务队列

 

2、作用:可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行(分布式)

 

3、应用场景:

(1)异步任务( async task ):发送邮件、或者文件上传, 图像处理等等一些比较耗时的操作

(2)定时任务( crontab ):在特定时间执行的任务

 

4、架构组成:

python Celery定时任务 celery定时任务原理_python Celery定时任务

 

二、基本概念:

1、任务队列 / celery:

任务队列是一种跨线程、跨机器工作的一种机制.

任务队列中包含称作任务的工作单元。有专门的工作进程持续不断的监视任务队列,并从中获得新的任务并处理.其构成如上图所示。

 

2、任务模块:

包含异步任务和定时任务。其中,异步任务(async task)通常在业务逻辑中被触发并发往任务队列,而定时任务由 Celery Beat进程周期性地将任务发往任务队列。

在定时任务中,celery beat:任务调度器。beat进程会读取配置文件里的内容(celerybeat_schedule里设置),周期性的将配置中到期需要执行的任务发送到任务队列。

 

3、消息中间件 Broker:

Broker ,即为任务调度队列,接收任务生产者发来的消息(即任务),将任务存入队列。 Celery 本身不提供队列服务,官方推荐使用 RabbitMQ 和 Redis 等。

 

4、任务执行单元 Worker:

Worker 是执行任务的处理单元,它实时监控消息队列,获取队列中调度的任务,并执行它。

 

5、任务结果存储 Backend:

Backend 用于存储任务的执行结果,以供查询。同消息中间件一样,存储也可使用 RabbitMQ, Redis 和 MongoDB 等

 

 

 

三、使用 Celery 实现异步任务的步骤:

(1) 创建一个 Celery 实例

(2) 启动 Celery Worker ,通过delay() 或 apply_async()(delay 方法封装了 apply_async, apply_async支持更多的参数 ) 将任务发布到broker

(3) 应用程序调用异步任务

(4)存储结果 (发布的任务需要return才会有结果,否则为空)

 

 

四、使用 Celery 实现定时任务的步骤:

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

(1) 创建一个 Celery 实例

(2) 配置文件中配置任务 ,发布任务 celery A xxx beat

(3) 启动 Celery Worker

(4) 存储结果

 

 

五、定时任务命令:

1、定时方式:

from celery.schedules import crontab
from datetime import timedelta
......

方式一:
 "schedule": timedelta(seconds=30), # hours=xx,minutes=xx 每小时/每分钟  (此项可以精确到秒)
# "schedule": crontab() # 与crontab的语法基本一致
# "schedule": crontab(minute="*/10",  # 每十分钟执行
# "schedule": crontab(minute="*/1"),   # 每分钟执行
# "schedule": crontab(minute=0, hour="*/1"),    # 每小时执行
方式二: "schedule": crontab(minute="*/10"), # every 10 minutes

2、相关命令:

# 发布任务:celery -A 路径.celery_app beat
eg: celery -A celery_app.app beat
# 执行任务:celery -A 路径.celery_app worker
celery -A celery_app.app worker --loglevel=info

3、执行完毕后会在当前目录下产生一个二进制文件,celerybeat-schedule 。

该文件用于存放上次执行结果:
  1、如果存在celerybeat-schedule文件,那么读取后根据上一次执行的时间,继续执行。
  2、如果不存在celerybeat-schedule文件,那么会立即执行一次。
  3、如果存在celerybeat-schedule文件,读取后,发现间隔时间已过,那么会立即执行。

 

六、celery定时任务简单使用

 1、目录结构如下

celery_task
├── celeryconfig.py    # celeryconfig配置文件
├── celery_app.py   # celery对象
├── epp_scripts   # 任务函数
│   ├── __init__.py
│   ├── test1.py
│   ├── test2.py
├── __init__.py

2、celery对象文件:celery.py

# coding:utf-8
# from __future__ import absolute_import  # 拒绝隐式引入,因为celery.py的名字和celery的包名冲突,需要使用这条语句让程序正确地运行
from celery import Celery

# 创建celery应用对象
app = Celery("celery_demo")

# 导入celery的配置信息
app.config_from_object("celeryconfig")

3、celery配置文件:celeryconfig.py

from __future__ import absolute_import  # 拒绝隐式引入,因为celery.py的名字和celery的包名冲突,需要使用这条语句让程序正确地运行
from celery.schedules import crontab
from datetime import timedelta

broker_url = "redis://127.0.0.1:6379/1"   # 使用redis存储任务队列
result_backend = "redis://127.0.0.1:6379/2"  # 使用redis存储结果

task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']
timezone = "Asia/Shanghai"  # 时区设置
worker_hijack_root_logger = False  # celery默认开启自己的日志,可关闭自定义日志,不关闭自定义日志输出为空
result_expires = 60 * 60 * 24  # 存储结果过期时间(默认1天)

# 导入任务所在文件
imports = [
    "epp_scripts.test1",  # 导入py文件
    "epp_scripts.test2",
]


# 需要执行任务的配置
beat_schedule = {
    "test1": {
        "task": "epp_scripts.test1.celery_run",  # 执行的函数
        "schedule": timedelta(minutes=1),   # every minute 每分钟执行
        "args": ()  # # 任务函数参数
    },

    "test2": {
        "task": "epp_scripts.test2.celery_run",
        "schedule": timedelta(minutes=2),   # every minute 每小时执行
        "args": ()
    },

}

3、任务函数:

# test1.py
from celery_app import app


def test11():
    print("test11----------------")


def test22():
    print("test22--------------")
    test11()


@app.task
def celery_run():
    test11()
    test22()


if __name__ == '__main__':
    celery_run()


# test2.py
from celery_app import app


def test33():
    print("test33----------------")
    # print("------"*50)


def test44():
    print("test44--------------")
    # print("------" * 50)
    test33()


@app.task
def celery_run():
    test33()
    test44()


if __name__ == '__main__':
    celery_run()

 

4、发布任务:beat把任务发送到broker(这里broker用的是本地redis,记得要启动redis,默认队列名:celery,数据类型是list)

# 在celery_task目录下执行:celery -A celery_app.app beat
(venv) ➜  celery_task celery -A celery_app.app beat
celery beat v5.0.5 (singularity) is starting.
__    -    ... __   -        _
LocalTime -> 2021-01-14 17:50:18
Configuration ->
    . broker -> redis://127.0.0.1:6379/1
    . loader -> celery.loaders.app.AppLoader
    . scheduler -> celery.beat.PersistentScheduler
    . db -> celerybeat-schedule
    . logfile -> [stderr]@%WARNING
    . maxinterval -> 5.00 minutes (300s)

5、查看消息中间件broker:

可以看到消息中间件redis中的默认消息队列celery,已经有2个任务

127.0.0.1:6379[1]> keys *
1) "_kombu.binding.celery"
2) "celery"
127.0.0.1:6379[1]> llen "celery"
(integer) 2

6、启动worker执行任务:在celery_task目录下执行:celery -A celery_app.app worker --loglevel=info

(venv) ➜  celery_task celery -A celery_app.app worker  --loglevel=info
-------------- celery@JS10226.local v5.0.5 (singularity)
--- ***** ----- 
-- ******* ---- Darwin-17.7.0-x86_64-i386-64bit 2021-01-14 17:51:02
- *** --- * --- 
- ** ---------- [config]
- ** ---------- .> app:         celery_demo:0x106282810
- ** ---------- .> transport:   redis://127.0.0.1:6379/1
- ** ---------- .> results:     redis://127.0.0.1:6379/2
- *** --- * --- .> concurrency: 6 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery
                

[tasks]
  . epp_scripts.test1.celery_run
  . epp_scripts.test2.celery_run

[2021-01-14 17:51:02,904: INFO/MainProcess] Connected to redis://127.0.0.1:6379/1
[2021-01-14 17:51:02,911: INFO/MainProcess] mingle: searching for neighbors
[2021-01-14 17:51:03,932: INFO/MainProcess] mingle: all alone
[2021-01-14 17:51:03,953: INFO/MainProcess] celery@JS10226.local ready.
[2021-01-14 17:51:04,096: INFO/MainProcess] Received task: epp_scripts.test2.celery_run[78071f3b-053f-45a9-a608-2db031396aa4]  
[2021-01-14 17:51:04,097: INFO/MainProcess] Received task: epp_scripts.test1.celery_run[08c64bb0-df09-4bd4-b53f-31727d2c503b]  
[2021-01-14 17:51:04,098: WARNING/ForkPoolWorker-4] test33----------------
[2021-01-14 17:51:04,098: WARNING/ForkPoolWorker-4] test44--------------
[2021-01-14 17:51:04,099: WARNING/ForkPoolWorker-4] test33----------------
[2021-01-14 17:51:04,099: WARNING/ForkPoolWorker-1] test11----------------
[2021-01-14 17:51:04,099: WARNING/ForkPoolWorker-1] test22--------------
[2021-01-14 17:51:04,099: WARNING/ForkPoolWorker-1] test11----------------
[2021-01-14 17:51:04,106: INFO/ForkPoolWorker-4] Task epp_scripts.test2.celery_run[78071f3b-053f-45a9-a608-2db031396aa4] succeeded in 0.008798735000000057s: None
[2021-01-14 17:51:04,106: INFO/ForkPoolWorker-1] Task epp_scripts.test1.celery_run[08c64bb0-df09-4bd4-b53f-31727d2c503b] succeeded in 0.007856532999999999s: None

  

本文参考自:celery定时任务简单使用