Celery-4.1 用户指南: Application(应用)
Application
Celery 库在使用之前必须初始化,一个celery实例被称为一个应用(或者缩写 app)。
Celery 应用是线程安全的,所以多个不同配置、不同组件、不同任务的 应用可以在一个进程空间里共存。
下面创建一个 celery 应用:
>>> from celery import Celery
>>> app = Celery()
>>> app
<Celery __main__:0x100469fd0>
最后一行显示的是 celery 应用的文本表示: 包含应用类的名称(Celery),当前主模块的名称(main),以及应用对象的内存地址(0x100469fd0)。
Main Name
上述文本表示中只有一部分是重要的,那就是主模块名称。下面分析下它为何重要。
当你发送一个消息给 Celery,消息中不会包含任何源码,而只有你想要执行的任务的名称。这就好像因特网上的域名映射原理一般:每个执行单元维护着一个任务名称到实际任务函数的映射,这个映射被称为任务注册表。
当你定义一个任务,这个任务就会被添加到本地注册表:
>>> @app.task
... def add(x, y):
... return x + y >>> add
<@task: __main__.add> >>> add.name
__main__.add >>> app.tasks['__main__.add']
<@task: __main__.add>
现在,你又看到显示 __main__
模块名称;当Celery不能探查到这个任务函数属于哪个模块时,它将使用主模块名称来产生任务名称的前缀。
这在有些情况下会产生问题:
1. 定义任务的主模块作为一个程序运行。
2. 应用在python交互终端创建。
例如下面程序,定义任务的模块还调用 app.worker_main()
来启动一个工作单元:
tasks.py:
from celery import Celery
app = Celery() @app.task
def add(x, y): return x + y if __name__ == '__main__':
app.worker_main()
当这个模块运行,任务将以前缀 __main__
命名,但是当该模块被其他进程引入来运行一个任务,这个任务的名称将以前缀 tasks
命名(即这个模块的真实名称)。
>>> from tasks import add
>>> add.name
tasks.add
你可以给主模块声明另外一个名称:
>>> app = Celery('tasks')
>>> app.main
'tasks' >>> @app.task
... def add(x, y):
... return x + y >>> add.name
tasks.add
具体可以查看名称这节。
配置
你可以设置一些选项来改变 Celery 的工作方式。这些选项可以直接在 app 实例上进行设置,或者也可以使用一个指定的配置模块。
配置使用 app.conf
变量保存:
>>> app.conf.timezone
'Europe/London'
你可以直接设置配置值:
>>> app.conf.enable_utc = True
或者使用 update
方法同时更新多个配置项。
>>> app.conf.update(
... enable_utc=True,
... timezone='Europe/London',
...)
实际的配置对象由多个字典决定,配置项按以下顺序查询:
1. 运行时的配置修改
2. 配置模块(如果声明)
3. 默认配置(celery.app.defaults)
你还可以使用 app.add_defaults()
方法添加新的默认配置源。
另外: 所有可用配置的完整列表及其默认值请参照 Configuration reference。
config_from_object
app.config_from_object() 方法从一个配置对象加载配置。
它可以是一个配置模块,或者任意包含配置属性的对象。
注意任何前面设置的配置在调用 config_from_object
方法后都将被重置。如果你想设置附加的配置应该在调用这个方法之后。
示例1: 使用模块名
app.config_from_object()
方法的参数可以是一个 python 模块的全限定名称,或者一个 python 属性名,例如:”celeryconfig”,”myproj.config.celery”,或者 “myproj.config:CeleryConfig”:
from celery import Celery app = Celery()
app.config_from_object('celeryconfig')
celeryconfig 模块内容如下形式:
celeryconfig.py:
enable_utc = True
timezone = 'Europe/London'
只要 import celeryconfig
能正常运行,应用实例就能加载它。
示例2:传递一个模块对象
你还可以传递一个已经加载的模块对象,但是不作为常规建议。
提示:
建议使用模块名的方式加载,因为这种情况下当prefork池使用时,配置模块不必序列化。如果遇到配置问题或者序列化错误,可以尝试使用模块名的方式加载配置。
import celeryconfig from celery import Celery app = Celery()
app.config_from_object(celeryconfig)
示例3:使用配置类/对象
from celery import Celery app = Celery() class Config:
enable_utc = True
timezone = 'Europe/London' app.config_from_object(Config)
# or using the fully qualified name of the object:
# app.config_from_object('module:Config')
config_from_envvar
app.config_from_envvar()
从环境变量中获取配置模块名称。
例如,从环境变量 CELERY_CONFIG_MODULE 所声明的模块加载配置:
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')
你可以通过环境变量声明要使用的模块:
$ CELERY_CONFIG_MODULE="celeryconfig.prod" celery worker -l info
敏感配置
如果你想打印配置信息,作为调试信息或者类似,你也许不想暴露密码和API秘钥这类信息。
Celery 提供了一些有用的工具函数来展示这些配置信息,其中一个是 humanize()
函数:
>>> app.conf.humanize(with_defaults=False, censored=True)
请注意Celery不会移除所有的敏感信息,因为它只是仅仅使用一个正则表达式来匹配配置项键名。如果你添加包含敏感信息的定制化配置,你应该使用 celery 能识别为敏感信息的键名。
如果一个配置项键名包含以下字符串,它将被看作是敏感的: API,TOKEN,KEY,SECRET,PASS,SIGNATURE,DATABASE
延迟加载
一个应用实例是延迟加载的,意味着它只有在实际调用的时候才会被求值。
创建一个celery 实例只会做如下事情:
1. 创建一个用于事件的逻辑时钟实例
2. 创建一个任务注册表
3. 将自己设置为当前应用实例(如果 set_as_current
参数被禁用将不会做此设置)
4. 调用 app.on_init()
回调函数(默认不做任何事情)
app.task()
装饰器在任务定义时不会创建任务,而是延迟任务的创建到任务使用时,或者应用被终止时。
下面这个例子说明了直到你使用任务时或者访问任务对象的属性时(这里是 repr()
)任务才会被创建:
>>> @app.task
>>> def add(x, y):
... return x + y >>> type(add)
<class 'celery.local.PromiseProxy'> >>> add.__evaluated__()
False >>> add # <-- causes repr(add) to happen
<@task: __main__.add> >>> add.__evaluated__()
True
应用的终止有两种情况,显示调用 app.finalize()
终止,或者通过访问 app.tasks
属性隐示终止。
终止应用对象将会执行:
1. 应用间必须共享的任务的拷贝
任务默认是被共享的,但是如果任务装饰器的共享参数被设置为禁用时任务会为被绑定的应用所私有。
对所有未求值的任务求值
确认所有任务都绑定到当前应用实例
任务绑定到了应用实例,所以可以读取配置的默认值。
note:
“默认应用实例”
celery 并不是一开始有应用实例这个概念,最早只有一个模块级别的API,为了向后兼容老的API,这个模块级别API会保留直到celery 5.0发布。
celery 会创建一个特殊的应用实例 - 默认应用实例,如果没有自定义的应用实例被初始化,这个默认应用实例将会被启用。
例如,老的任务基类使用了许多兼容特性,其中一些与新的特性不兼容,比如任务方法。
from celery.task import Task # << OLD Task base class. from celery import Task # << NEW base class.
即使你使用老的模块级别的API,也推荐使用新的基类。
打破链式操作
虽然可以依赖于当前设置的应用实例,但是将应用实例作为参数传递给所有需要它的对象仍然是最佳操作实践。
称这种操作为“应用实例链”的原因是因为它依赖所传递的应用实例创建了一个链。
下面这个例子被认为是差的实践:
from celery import current_app class Scheduler(object): def run(self):
app = current_app
它应用将 app 作为一个参数传递:
class Scheduler(object): def __init__(self, app):
self.app = app
在celery内部实现中,使用 celery.app_or_default()
函数使得模块级别的 API 也能正常使用。
from celery.app import app_or_default class Scheduler(object):
def __init__(self, app=None):
self.app = app_or_default(app)
在开发环境中,可以通过设置 CELERY_TRACE_APP
环境变量在应用实例链被打破时抛出一个异常:
$ CELERY_TRACE_APP=1 celery worker -l info
note:
API 的演化
celery 项目从开始创建到现在的七年多时间里已经改变了很多。
例如,最开始可以使用任何一个可调用对象作为一个任务:
def hello(to):
return 'hello {0}'.format(to) >>> from celery.execute import apply_async >>> apply_async(hello, ('world!',))
可以创建一个任务类,设置特定属性,或者覆盖其他行为
from celery.task import Task
from celery.registry import tasks class Hello(Task):
queue = 'hipri' def run(self, to):
return 'hello {0}'.format(to)
tasks.register(Hello) >>> Hello.delay('world!')
后来,开发者觉得传递任意可调用对象是反模式,因为它使得很难使用除了 pickle
之外的序列化方案,因此这个特性在 2.0 就被踢除了,取而代之的是任务装饰器:
from celery.task import task @task(queue='hipri')
def hello(to):
return 'hello {0}'.format(to)
抽象任务
所有使用 task() 装饰器创建的任务都会继承应用的基础 Task
类。
你可以使用装饰器的 base 参数给任务声明一个不同的基类:
@app.task(base=OtherTask):
def add(x, y):
return x + y
创建一个自定义的任务类,你应该继承这个中性类:celery.Task
from celery import Task class DebugTask(Task): def __call__(self, *args, **kwargs):
print('TASK STARTING: {0.name}[{0.request.id}]'.format(self))
return super(DebugTask, self).__call__(*args, **kwargs)
提示:
如果你覆盖了任务的 __call__
方法,那么非常重要的一点是你还需要调用父类的方法使得在任务被直接调用时基类call方法能设置好默认请求。
这个中性类比较特殊,因为它不会绑定到任意特殊应用实例。一旦任务绑定到一个应用实例,它将读取应用的配置信息来设置默认值等等。
使用一个基类,你需要使用 app.task()
装饰器创建一个任务:
@app.task(base=DebugTask)
def add(x, y):
return x + y
还可以通过修改 app.Task
属性来修改一个应用实例的默认基类:
>>> from celery import Celery, Task >>> app = Celery() >>> class MyBaseTask(Task):
... queue = 'hipri' >>> app.Task = MyBaseTask
>>> app.Task
<unbound MyBaseTask> >>> @app.task
... def add(x, y):
... return x + y >>> add
<@task: __main__.add> >>> add.__class__.mro()
[<class add of <Celery __main__:0x1012b4410>>,
<unbound MyBaseTask>,
<unbound Task>,
<type 'object'>]
转自:https://blog.csdn.net/libing_thinking/article/details/78541171
Celery-4.1 用户指南: Application(应用)的更多相关文章
- Android官方技术文档翻译——Gradle 插件用户指南(5)
昨晚把第五章未译完的几句话攻克了.只是第六章没怎么译,明后天又是周末,假设周一前第六章翻译完的话,周一再发第六章. 本文译自Android官方技术文档<Gradle Plugin User Gu ...
- 阿里云API网关(5)用户指南(调用 API)
网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...
- Gradle 1.12用户指南翻译——第二十二章. 标准的 Gradle 插件
其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...
- 【翻译】Flume 1.8.0 User Guide(用户指南) Sink
翻译自官网flume1.8用户指南,原文地址:Flume 1.8.0 User Guide 篇幅限制,分为以下5篇: [翻译]Flume 1.8.0 User Guide(用户指南) [翻译]Flum ...
- 【翻译】Flume 1.8.0 User Guide(用户指南) source
翻译自官网flume1.8用户指南,原文地址:Flume 1.8.0 User Guide 篇幅限制,分为以下5篇: [翻译]Flume 1.8.0 User Guide(用户指南) [翻译]Flum ...
- Opera Unite 用户指南
Opera Unite 用户指南 1 Opera Unite 简介 Opera Unite is a collaborative technology that allows you to share ...
- dubbo用户指南
用户指南 入门 背景 需求 架构 用法 快速启动 服务提供者 服务消费者 依赖 必需依赖 缺省依赖 可选依赖 成熟度 功能成熟度 策略成熟度 配置 Xml配置 属性配置 注解配置 API配置 示例 启 ...
- 《gradle 用户指南中文版》目录
gradle 用户指南 版权所有©2007-2017 Hans Dockter,Adam Murdoch只要您不对这些副本收取任何费用,并且进一步规定,每个副本都包含本版权声明,无论是以印刷版还是电子 ...
- dubbo用户指南-总结
dubbo用户指南-总结 入门 背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用 ...
随机推荐
- nginx根据项目名实现内网地址转发
nginx根据访问的项目名进行内网地址转发 以下是nginx的配置信息: server { listen 8081; server_name localhost; #charset koi8-r; # ...
- mysql基础(3)-高级查询
聚合函数 count 返回查询结果的条数 max 返回查询结果的最大值 min 返回查询结果的最小值 sum 返回查询结果的和 avg 返回查询结果的平均值 统计分数大于等于90的人数: mysq ...
- SolrCloud 5.5.5 + Zookeeper + HDFS使用
安装sol r 三个节点192.168.1.231,192.168.1.234,192.168.1.235 下载安装包solr.tar.gz 解压 tar -zxvf solr.tar.gz 配置ZK ...
- android、ipone在文本框中输入文字的不同
1.android机会输入时会在键盘上先显示,你确定后再填充如文本框 2.ipone机是你输入时就直接填充到文本框,当你选择输入信息时,就会先把文本框的内容清空,在填充选择的文字,这时就会有个问题,如 ...
- QT 学习记录:渐变-QLinearGradient,QRadialGradient,QConicalGradient)
http://blog.csdn.net/wangwei890702/article/details/8552482 QT:渐变 渐变,是指逐渐的,有规律性的变化,是一种规律性很强的现象.Qt提供了一 ...
- SPFA算法O(kE)
SPFA算法O(kE) Dijkstra和Floyed是不断的试点.Dijkstra试最优点,Floyed试所有点. Bellman-Ford和SPFA是不断的试边.Bellman-Ford是盲目的试 ...
- hdu 1849 Rabbit and Grass(nim)
Rabbit and Grass Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HANA IMPORT AND EXPORT
权限管控的过于严格,所以找机会写个导入导出的流程.从测试机传输到生产机 1 选中EXPORT , 导出将要传输的模型 也可以 在QUICK VIEW 里选中导入导出.个人爱好 2 选择传输的两种模式 ...
- 28 python 并发编程之多进程
一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.P ...
- java学习笔记 --- 网络编程(套接字)
1.Socket通信原理 Socket套接字概述: 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字. 通信的两端都有Socket. 网络通信其实就是Socket间的通信 ...