Celery 工程构建demo

Our Project

当前项目的文件结构:

[root@VM_0_2_centos test002]# tree
.
|-- app.py
|-- celeryconfig.py

0 directories, 2 files

下面对每一个文件进行详细地说明。

celery.py

from __future__ import absolute_import, unicode_literals

from celery import Celery

# app = Celery('proj',
#              broker='redis://127.0.0.1:6379',
#              backend='redis://127.0.0.1:6379/0',
#              include=['proj.tasks'])

app = Celery('proj', include = ['proj.tasks'])
app.config_from_object('proj.celeryconfig')

# Optional configuration, see the application user guide.
app.conf.update(
    result_expires=3600,
)

if __name__ == '__main__':
    app.start()

celeryconfig.py

# backend and broker

BROKER_URL = 'redis://127.0.0.1:6379'
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/0'

app.pycelery应用的切入口,celeryconfig.py中存放着celery的相关配置。

配置文件中: BROKER_URL对应消息中间件,RESULT_BACKEND存储任务的执行结果。

接着,定义tasks.py

tasks.py

from __future__ import absolute_import, unicode_literals

from .celery import app

@app.task
def add(x, y):
    return x + y

@app.task
def mul(x, y):
    return x * y

@app.task
def xsum(numbers):
    return sum(numbers)

Starting the worker

启动worker

[root@VM_0_2_centos test002]# celery -A app worker -l info
/usr/lib64/python2.7/site-packages/celery/platforms.py:801: RuntimeWarning: You're running the worker with superuser privileges: this is
absolutely not recommended!

Please specify a different user using the --uid option.

User information: uid=0 euid=0 gid=0 egid=0

  uid=uid, euid=euid, gid=gid, egid=egid,

 -------------- celery@VM_0_2_centos v4.4.2 (cliffs)
--- ***** -----
-- ******* ---- Linux-3.10.0-693.el7.x86_64-x86_64-with-centos-7.7.1908-Core 2020-04-02 16:19:44
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app:         tasks:0x7f18c8eda110
- ** ---------- .> transport:   redis://127.0.0.1:6379//
- ** ---------- .> results:     redis://127.0.0.1:6379/0
- *** --- * --- .> concurrency: 1 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[tasks]


[2020-04-02 16:19:44,958: INFO/MainProcess] Connected to redis://127.0.0.1:6379//
[2020-04-02 16:19:44,987: INFO/MainProcess] mingle: searching for neighbors
[2020-04-02 16:19:47,027: INFO/MainProcess] mingle: all alone
[2020-04-02 16:19:47,038: INFO/MainProcess] celery@VM_0_2_centos ready.

这里添加,官方文档中的补充说明。

  1. broker: 可以在配置文件中指定URL,同样也可以使用-b选项在命令行中指定其他的代理。

  2. concurrency: 同时处理任务的prefork的数目[1]。当所有prefork都处于执行任务阶段,新任务将等待某个任务完成,才能被处理。

  3. events: events用于触发Celery发送监视消息以监视工作程序中发生的操作。

  4. queues: 队列是worker使用任务的队列列表。

Stopping the worker

  1. 使用ctrl + C

  2. pkill -9 -f 'celery worker'

  3. ps auxww | awk '/celery worker/ {print $2}' | xargs kill -9

官方文档 http://docs.celeryproject.org/en/master/userguide/workers.html#stopping-the-worker

In the background

后台运行的方法: 这一步骤先跳过

官方文档 http://docs.celeryproject.org/en/master/userguide/daemonizing.html#daemonizing

Calling Tasks

调用tasks.py中的add方法:

调用deplay()方法

>>> from proj.tasks import add
>>> res = add.delay(2, 2)
>>> res.get()
4

调用apply_async()方法

apply_async方法, deplay方法实际是apply_async方法的简化版本。apply_async可以支持多个参数。

>>> res = add.apply_async((2, 2))
>>> res.get()
4

apply_async可以指定执行选项,例如原型时间(倒数),应当发送的队列等等。

add.apply_async((2, 2), queue = 'lopri', countdown = 10)

>>> res = add.apply_async((2, 2), queue = 'lopri', countdown = 0.5)
>>> res.get()

此示例中,该任务将被发送到lopri的队列中,并且此任务最早将在发送消息10秒后执行[4]。

等待很长时间,没有得到返回值。

直接调用方法

>>> add(2, 2)
4

直接调用方法,不会触发消息的发送worker

官方文档call方法: http://docs.celeryproject.org/en/master/userguide/calling.html#guide-calling

查看任务 id

>>> res = add.delay(2, 2)
>>> res.id
'b022ce12-08e3-442b-8cf9-05d77e12c412

查看任务执行情况

>>> res.failed()
False
>>> res.successful()
True

查看任务执行状态

>>> res.state
'SUCCESS'

任务状态的演进

PENDING -> STARTED -> SUCCESS

pending状态

pending状态,是未知任务ID的默认状态

>>> from proj.celery import app
>>> res = app.AsyncResult('this-id-does-not-exist')
>>> res.state
u'PENDING'

重复启动状态

PENDING -> STARTED -> RETRY -> STARTED -> RETRY -> STARTED -> SUCCESS

Canvas: Designing Work-flows

有时需要将任务调用的签名传递给另一个进程,或者作为另一个函数的参数。Celery为此使用了一种称为签名的函数。

签名将包装单个任务调用的参数和执行选项,以便可以将其传递给函数,甚至进行序列化并通过网络发送。

可以使用参数(2, 2)和10秒的倒计时为添加任务创建签名,如下所示:

>>> from proj.tasks import add
>>> add.signature((2, 2))
proj.tasks.add(2, 2)
>>> add.s(2, 2)
proj.tasks.add(2, 2)

这里没有看懂是什么意思?

And there’s that calling API again …

签名实例支持调用API, 意味着具有delay和apply_async方法,区别于签名已经指定了参数签名,add任务接受两个参数,因此指定两个参数的签名将构成完整的签名:

>>> s1 = add.signature((2, 2))
>>> res = s1.delay()
>>> res.get()
4

可以创建不完整的签名来创建partials的部分。

s2是部分签名,需要另一个参数来完成,可以在调用签名时解决。

>>> s2 = add.s(2)           # incomplete partial: add(?, 2)
>>> res = s2.delay(8)       # resolves the partial: add(8, 2)
>>> res.get()
10

直观感受,可以利用signature先补充一个参数,然后通过delay在补充另一个参数。

官方解释,在这里在现有的参数2前添加了参数8, 形成了add(8, 2)的完整签名。

参考文档

1. 官方文档 http://docs.celeryproject.org/en/master/getting-started/next-steps.html#next-steps

问题汇总

  1. 同时处理任务的prefork的数目. prefork数目对应什么?

    答: prefork数目,对应该计算机(包括核心)上的CPU数目。

  2. events是什么?具体如何实践?

  3. queues是什么?具体如何实践?

  4. add.apply_async((2, 2), queue = 'lopri', countdown = 10), 此队列lopri是任意指定的吗?

  5. Canvas: Designing Work-flows 模块是干什么用的?

发布了21 篇原创文章 · 获赞 0 · 访问量 2611

猜你喜欢

转载自blog.csdn.net/u012720518/article/details/105281876
今日推荐