在 jumpserver 中 通过 很多异步执行的task,从task 入口 了解下celery 的机制过程。
首先callable 对象 都可以被当作 实例化成task,主要 是由装饰器 实现得,一种是 @app.taks 实现得 ,从这开始 作为一个入口,来看看 task 的实例化过程以及调用过程。自己写了个小demo debug 了解 task 实例化过程中 一步一步 具体的执行流程 ,最后一步是这样的,出现了 调用这个方法,返回了task。
def _task_from_fun(self, fun, **options):
if not self.finalized and not self.autofinalize:
raise RuntimeError('Contract breach: app not finalized')
base = options.pop('base', None) or self.Task
bind = options.pop('bind', False)
T = type(fun.__name__, (base, ), dict({
'app': self,
'accept_magic_kwargs': False,
'run': fun if bind else staticmethod(fun),
'_decorated': True,
'__doc__': fun.__doc__,
'__module__': fun.__module__,
'__wrapped__': fun}, **options))()
task = self._tasks[T.name] # return global instance.
return task
这个 task 对象是由元类 创造出来得,关于 元类type 怎么创造 对象,这个需要以后仔细说一说。
当一个 函数被 装饰成 task 时,这个 task 就是一个全局得对象。
from celery import Celery
app = Celery('tasks', broker='amqp://[email protected]:15672//')
@app.task
def add(x, y):
result = x + y
return result
调用的时候 应该这么写
from tasks import add
add.delay(1,2)
这个调用过程应该是怎样的?调用 的过程会把函数 用到的参数传进去,然后会调用 apply_async 方法。apply_async 主要是以消息形式 将 task 发送出去,而 发送消息 的客户端 主要是借助 python 消息库kombu 。而 kombu 主要作用是 实现了 一个客户端 跟 rabbitmq 或者redis 也就是broker 交互。具体源码如下,主要通过 kombu 的ensure 方法 是 建立了publish 对象 来实现发送消息。
def ensure(self, obj, fun, errback=None, max_retries=None,
interval_start=1, interval_step=1, interval_max=1,
on_revive=None):
"""Ensure operation completes, regardless of any channel/connection
errors occurring.
Will retry by establishing the connection, and reapplying
the function.
:param fun: Method to apply.
:keyword errback: Optional callback called each time the connection
can't be established. Arguments provided are the exception
raised and the interval that will be slept ``(exc, interval)``.
:keyword max_retries: Maximum number of times to retry.
If this limit is exceeded the connection error will be re-raised.
:keyword interval_start: The number of seconds we start sleeping for.
:keyword interval_step: How many seconds added to the interval
for each retry.
:keyword interval_max: Maximum number of seconds to sleep between
each retry.
**Example**
This is an example ensuring a publish operation::
>>> from kombu import Connection, Producer
>>> conn = Connection('amqp://')
>>> producer = Producer(conn)
>>> def errback(exc, interval):
... logger.error('Error: %r', exc, exc_info=1)
... logger.info('Retry in %s seconds.', interval)
>>> publish = conn.ensure(producer, producer.publish,
... errback=errback, max_retries=3)
>>> publish({'hello': 'world'}, routing_key='dest')
"""
kombu 真是一个非常好的库,暴露出的接口非常简单,内部实现很好。
以上大概理解了 生产端的 代码逻辑,下面看消费端的代码实现。
当消费端 也就是 worker 开始消费 消息命令如下。这是个坑,以后再补。