任務
任務是 Celery 裏不可缺少的一部分,它可以是任何可調用對象。每一個任務通過一個唯一的名稱進行標識, worker 通過這個名稱對任務進行檢索。任務可以通過 app.task 裝飾器進行註冊,需要注意的一點是,當函數有多個裝飾器時,爲了保證 Celery 的正常運行,app.task 裝飾器需要在最外層。
# 裝飾器示例
@app.task
@decorator2
@decorator1
def add(x, y):
return x + y
同時,app.task 裝飾器也接受多種參數對任務進行配置。例如,可以通過 name 顯式的設定任務的名字,serializer 設定任務的序列化方式。
@app.task(name='task.add', serializer='json')
def add(x, y):
return x + y
還有一個比較重要的是 bind 參數,當設置了 bind 參數,則會爲這個任務綁定一個 Task 實例,通過第一個 self 參數傳入,可以通過這個 self 參數訪問到 Task 對象的所有屬性。
logger = get_task_logger(__name__)
@task(bind=True)
def add(self, x, y):
logger.info(self.request.id)
完整的參數列表可以看這裏 Task Option
任務執行
前面介紹到,可以通過 delay 使用 Celery 執行一個任務,實際上 delay 是 apply_async 的一個快捷方式,而相較於 delay,apply_aysnc 支持對於任務執行過程的更精確的控制。比如下面這個例子的 countdown 參數表示在接收到任務 10 秒後開始執行。
>>> add.apply_async((1, 2), countdown=10)
<AsyncResult: 16af1a5f-b546-4f7c-b113-0e861c175144>
函數原型如下,
task.apply_async(args[, kwargs[, …]])
其中 args 和 kwargs 分別是 task 接收的參數,當然它也接受額外的參數對任務進行控制。除此 countdown 之外,可以通過 expires 設置任務過期時間,當 worker 接收到一個過期任務,它的狀態會標記爲 REVOKE;也可以通過設置 retry=True,在任務執行失敗時進行重試。
*對於未註冊的函數,可以調用 Task 對象的 send_task 方法向任務隊列添加一個任務,通過 name 參數設定任務名進行標識,和 apply_aysnc 一樣返回一個 AsyncResult 對象。
所以總結一下,在 Celery 中執行任務的方法一共有三種:
1. delay, 用來進行最簡單便捷的任務執行;
2. apply_async, 對於任務的執行附加額外的參數,對任務進行控制;
3. app.send_task, 可以執行未在 Celery 中進行註冊的任務。
鏈式執行
在 Celery 中,可以通過調用 apply_async 時傳遞 link 參數設置任務執行完成後的後續任務,當然這個任務也會由 Celery 交給 worker 執行。這裏有一點需要注意,任務執行的返回值將會以參數的形式傳遞給這個後續任務,而這裏的後續任務需要是一個 signature 對象(關於 signature 對象在下一節詳細的介紹,這裏只需要知道 add.s(1) 語句將會創建一個 signature 對象,功能上類似於偏函數 functools.patial(add,1))。下面的例子等價於 add(add(1, 2), 3)
>>>add.apply_async((1, 2), link=add.s(3))
同樣的對於失敗的任務,可以用 linkerr 參數來指定回調函數。同時 link 和 linkerr 也支持將列表作爲參數,任務執行之後列表中的任務都會被加入隊列中繼續執行。使用link 和 linkerr 可以更好的規劃任務流程,在下一節可以看到使用 chain 函數可以更好的實現這個功能。
自定義 Task
可以通過繼承 celery.Task 的方式來定義自己的 Task 類,併爲你的 Task 類添加額外的功能。
import celery
class MyTask(celery.Task):
def on_failure(self, exc, task_id, args, kwargs, einfo):
print('{0!r} failed: {1!r}'.format(task_id, exc))
@task(base=MyTask)
def add(x, y):
raise KeyError()
和上面的 on_failure 類似,Task 對象中有一系列方法來控制任務執行,也可以通過重寫這些方法來爲任務添加回調函數,通過 base 參數來指定任務的基類。
這些方法功能如下,具體的方法定義看這裏 Task Handlers:
- after_return:在任務執行返回後交給 worker 執行
- on_failure:在任務執行失敗後交給 worker 執行
- on_retry:在任務進行重試是交給 worker 執行
- on_success:在任務執行成功後交給 worker 執行
import celery
class CountTask(celery.Task):
count = 0
def on_success(self, retval, task_id, args, kwargs):
self.count += 1
return self.count
@app.task(base=CountTask)
def send():
if send.count <= 10:
return 'Hello World'
else:
return 'end'
除此之外還可以通過自定義的 Task 類在多個任務間共享狀態,例如可以通過類屬性 count 來保存任務的成功執行次數,在任務中可以直接在函數上調用對應屬性來獲得 Task 類的屬性。