Celery 學習筆記(3)- 任務和任務執行

任務

任務是 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 類的屬性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章