Celery用户手册 - Application

Application

必须使用一个Application实例来创建celery 任务.

该Application线程是安全(thread-safe)的,以便你可以使用多个不同的Application 配置. 组件和任务能共存于相同的进程空间。

创建一个Application实例:

>>> from celery import Celery
>>> app = Celery()
>>> app
<Celery __main__:0x100469fd0>
<\>Python

最后一行显示的是此Application实例的文本描述,其中包括celery类的名称,此实例存在于__main__ 主模块中和此实例的内存地址.

Main Name

Main Name 是个很重要的概念, 以下会介绍为什么重要.

当你使用Celery 推送一个任务消息, 这个消息不携带任何的源代码,但是需要指定一个此消息需要执行的任务名称。这种工作方式类似于hostname工作方式, 在网络上: 每个worker维护着任务名和他们所能执行的实际函数. 这就是所谓的task registry(任务注册表).

每当你定义一个任务, 该任务也将要添加到本地的task registry

>>> @app.task
... def add(x, y):
...     return x + y
>>> add
<@task: __main__.add>
>>> add.name
__main__.add
>>> app.tasks['__main__.add'] # 根据task name取出实际函数(function)
<@task: __main__.add>
<\>Python

这里你会在此看到__main__ ,每当Celery无法检索到function属于哪个模块, 它会使用主模块名称生成任务模块, 即__main__.add.

这种现象只会出现在下面情况中:

  1. 定义的task所属的application 在一个主模块中
  2. 此application实例创建在Python 交互式环境中

第一种: tasks.py

from celery import Celery
app = Celery()

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

if __name__ == '__main__':
    app.worker_main()
<\>Python

当这个tasks.py 作为一个主模块执行的时候(__main__成立)任务名称以__main__开头, 即__main__.add. 但是当此模块被另外一个模块引用的时候,它的任务名称将以tasks开头, 即tasks.add.

>>> from tasks import add
>>> add.name
tasks.add
<\>Python

可以在创建的Application的时候指定一个名称.

>>> app = Celery('tasks')
>>> app.main
'tasks'

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

>>> add.name
tasks.add
<\>Python

参考: Names

Configuration

你可以设置Celery的其他选项,这些选项作用于application 实例. 但你最好单独定义一个配置模块。

查看一个配置

>>> app.conf.CELERY_TIMEZONE
'Europe/London'
<\>Python

你也可以直接设置配置项

>>> app.conf.CELERY_ENABLE_UTC = True
<\>Python

使用update方法更新多个键值.

>>> app.conf.update(
...     CELERY_ENABLE_UTC=True,
...     CELERY_TIMEZONE='Europe/London',
...)
<\>Python

配置对象可以通过多种方法去修改操作, 他们的优先级是:

  1. 运行时修改
  2. 配置模块(如果有的话)
  3. 默认配置模块(celery.app.defaults)

你甚至可以使用celery.add_defaults()方法来添加新的默认源.

参见: Configuration reference 查看支持的通用选项参数列表.

configfromobject

Celery.config_from_object() 可以从一个配置对象加载配置, 可以是一个配置模块, 或者其他配置属性的对象.

需要注意的是, 使用此方法后默认参数将会被重置, 如果配置对象的键值和默认对象有冲突的话。 如果你想设置额外的配置你应该在之后在此方法之后去设置.

Example 1: 使用name作为module

from celery import Celery

app = Celery()
app.config_from_object('celeryconfig')
<\>Python

celeryconfig 作为字符串对象传入, celeryconfig内容如下

celeryconfig.py: CELERY_ENABLE_UTC = True CELERY_TIMEZONE = 'Europe/London'

Example 2: 使用configtion module

from celery import Celery

app = Celery()
import celeryconfig
app.config_from_object(celeryconfig)
<\>Python

Example 3: 使用configtion class/object

from celery import Celery

app = Celery()

class Config:
    CELERY_ENABLE_UTC = True
    CELERY_TIMEZONE = 'Europe/London'

app.config_from_object(Config)
# or using the fully qualified name of the object:
#   app.config_from_object('module:Config')
<\>Python

configfromenvvar

使用Celery.config_from_envvar()方法可以从环境变量来设置选项.

从环境变量名为CELERYCONFIGMODULE加载配置:

import os
from celery import Celery

#: Set default configuration module name
os.environ.setdefault('CELERY_CONFIG_MODULE', 'celeryconfig')

app = Celery()
app.config_from_envvar('CELERY_CONFIG_MODULE')
<\>Python

然后你可以指定配置模块,通过设置环境变量的方法:

$ CELERY_CONFIG_MODULE="celeryconfig.prod" celery worker -l info
<\>Bash

Censored configuration

如果你想打印出配置, 但是你不想打印一些敏感的数据, 就像密码和API 密钥类似的敏感信息。

Celery 支持用于展示配置相关逻辑, 一个就是humanize():

>>> app.conf.humanize(with_defaults=False, censored=True)
<\>Python

此方法将会隐藏敏感信息, 如果with_defaults为true的话, 可以显示为默认的值。

默认情况下Celery认为配置KEY中包含API, TOKEN, KEY, SECRET, PASS, SIGNATURE, DATABASE这些字符的都为敏感信息。

Breaking the chain

并没有看懂这段 , 貌似讲的是一种规范.

Abstract Tasks

以上所有的tasks创建的时候都使用了task() 装饰器,task会继承Task class.

当然可以指定成其他的Task基类, 比如下面代码中base=OtherTask, 那么此task的基类为OtherTask.

@app.task(base=OtherTask):
def add(x, y):
    return x + y
<\>Python

如果你想创建一个自定义的Task 类, 你必须继承自celery.Task

from celery import Task

class DebugTask(Task):
    abstract = True

    def __call__(self, *args, **kwargs):
        print('TASK STARTING: {0.name}[{0.request.id}]'.format(self))
        return super(DebugTask, self).__call__(*args, **kwargs)
<\>Python

𝔔