Celery是如何工作的?
Celery 由於 其分散式體系結構,在某種程度上可能難以理解。下圖是典型Django-Celery設定的高階示意圖(FROM O'REILLY):
當請求到達時,您可以在處理它時呼叫Celery任務。呼叫任務的函式會立即返回,而不會阻塞當前程式。實際上,任務尚未完成執行,但是任務訊息已進入任務佇列(或許多可能的任務佇列之一)。
workers 是獨立的程式,用於監視任務佇列中是否有新任務並實際執行它們,他們拿起任務訊息、處理任務、儲存結果。
一、安裝一個broker
Celery需要一個傳送和接收訊息的解決方案,即一個訊息代理(message broker)服務,常用的broker包括:
RabbitMQ功能齊全,穩定,耐用且易於安裝,是生產環境的絕佳選擇。
Ubuntu安裝:
$ sudo apt-get install rabbitmq-server
Docker安裝:
$ docker run -d -p 5672:5672 rabbitmq
-
關於RabbitMQ在Celery中的高階配置,見:使用RabbitMQ
-
其他系統安裝RabbitMQ,見:下載並安裝RabbitMQ
Redis
Redis也具有完整的功能,但是在突然終止或電源故障的情況下更容易丟失資料。
Ubuntu安裝:
$ sudo apt install redis-server
Docker安裝:
$ docker run -d -p 6379:6379 redis
-
關於Redis在Celery中的高階配置:使用Redis
-
關於Redis的安裝:How to Install and Secure 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)
呼叫任務將返回一個AsyncResult
例項,這可用於檢查任務的狀態,等待任務完成或獲取其返回值(或者如果任務失敗,則獲取異常和回溯)
預設情況下執行任務不返回結果。為了執行遠端過程呼叫或跟蹤資料庫中的任務結果,需要配置result backend
。
六、獲取執行結果
如果要跟蹤任務的狀態,Celery需要將狀態儲存或傳送到某個地方。有多個result backend
可供選擇:SQLAlchemy / Django ORM, MongoDB,Memcached,Redis,RPC(RabbitMQ / 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() # 檢查是否完成任務,返回布林值
通過設定
@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