Celery:小試牛刀

BaKuai發表於2021-03-09

Celery是如何工作的?

Celery 由於 其分散式體系結構,在某種程度上可能難以理解。下圖是典型Django-Celery設定的高階示意圖(FROM O'REILLY):

Celery:小試牛刀

當請求到達時,您可以在處理它時呼叫Celery任務。呼叫任務的函式會立即返回,而不會阻塞當前程式。實際上,任務尚未完成執行,但是任務訊息已進入任務佇列(或許多可能的任務佇列之一)。

workers 是獨立的程式,用於監視任務佇列中是否有新任務並實際執行它們,他們拿起任務訊息、處理任務、儲存結果。


一、安裝一個broker

Celery需要一個傳送和接收訊息的解決方案,即一個訊息代理(message broker)服務,常用的broker包括:


RabbitMQ功能齊全,穩定,耐用且易於安裝,是生產環境的絕佳選擇。

Ubuntu安裝:

$ sudo apt-get install rabbitmq-server

Docker安裝:

$ docker run -d -p 5672:5672 rabbitmq

Redis

Redis也具有完整的功能,但是在突然終止或電源故障的情況下更容易丟失資料。

Ubuntu安裝:

$ sudo apt install redis-server

Docker安裝:

$ docker run -d -p 6379:6379 redis

二、安裝Celery

$ pip install celery

三、編寫Celery任務程式碼

首先匯入Celery,建立一個Celery物件,這個物件將作為一個操作 Celery 的入口,如建立任務,管理workers等。

以下示例會把所有東西都寫在一個模組中,但是對於大型專案,您需要建立一個專用模組

# tasks.py
import time
from celery import Celery

app = Celery('tasks', broker='pyamqp://guest@localhost//')

@app.task
def add(x, y):
    print('--------start---------')
    for i in range(5):
        print(f'第{i}秒')
    print('--------over----------')
    return x + y

第一個引數是當前模組的名稱,這是唯一的必需引數。

第二個引數指定要使用的訊息代理的URL。這裡使用RabbitMQ(也是預設選項)。

若使用Redis:

app = Celery('tasks', broker='redis://localhost:6379/0')

四、啟動 worker 程式

$ celery -A tasks worker --loglevel=INFO

在生產環境中,需要在後臺將工作程式作為守護程式執行。為此,需要使用 平臺提供的工具 或 類似supervisord的工具


五、呼叫任務

呼叫任務需要匯入帶有celery示例的模組,這裡沒有重新建立一個模組匯入,而是使用命令列模式。要呼叫我們定義的任務,可以使用delay()(詳情參閱 呼叫任務):

>>> from tasks import add
>>> add.delay(4, 4)
Celery:小試牛刀

呼叫任務將返回一個AsyncResult例項,這可用於檢查任務的狀態,等待任務完成或獲取其返回值(或者如果任務失敗,則獲取異常和回溯)

預設情況下執行任務不返回結果。為了執行遠端過程呼叫或跟蹤資料庫中的任務結果,需要配置result backend


六、獲取執行結果

如果要跟蹤任務的狀態,Celery需要將狀態儲存或傳送到某個地方。有多個result backend可供選擇:SQLAlchemy / Django ORM, MongoDBMemcachedRedisRPCRabbitMQ / AMQP)等。

下面使用 RPC 作為result backend,該後端將狀態作為瞬態訊息傳送回去。使用backend引數配置Celery物件的result backend

app = Celery('tasks', backend='rpc://', broker='pyamqp://')

或者,如果使用 Redis 作為result backend,但仍然使用 RabbitMQ 作為 broker(流行的組合):

app = Celery('tasks', backend='redis://localhost', broker='pyamqp://')

更多result backend配置參閱“result backend

我們再次呼叫該任務:

>>> result = add.delay(4, 4)
>>> result.ready() # 檢查是否完成任務,返回布林值
Celery:小試牛刀

通過設定@app.task(ignore_result=True)選項,也可以禁用單個任務返回結果,詳情見有關celery.result的完整參考


七、配置Celery

對於大多數使用情況,預設配置就夠了,但是可以配置更多選項使Celery根據需要工作。詳細配置見“配置和預設值”

可以直接在應用程式上設定配置,也可以使用專用的配置模組設定配置。例如配置用於序列化任務負載的預設序列化器:

# 配置一個設定:
app.conf.task_serializer = 'json'

# 一次配置許多設定,則可以使用update
app.conf.update(
    task_serializer='json',
    accept_content=['json'],  # Ignore other content
    result_serializer='json',
    timezone='Europe/Oslo',
    enable_utc=True,
)

對於較大的專案,建議使用專用的配置模組。

app.config_from_object('celeryconfig')

celeryconfig.py必須可用於從當前目錄或Python路徑中載入

celeryconfig.py

broker_url = 'pyamqp://'
result_backend = 'rpc://'

task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']
timezone = 'Europe/Oslo'
enable_utc = True

參考

相關文章