[英]Allow a task execution if it's not already scheduled using celery
我正在使用Celery來處理我正在開發的Django應用程序中的任務調度,我正在使用Django數據庫進行測試。
我只是想幾件事情要處理,只有當它不是已經計划任務的執行,或者在這樣的提議進步文章 ,到目前為止,但沒有工作。
像這樣的東西:
task.py
@task()
def add(x, y):
return x + y
然后當你按照以下方式調用它兩次時:
import myapp.tasks.add
myapp.tasks.add.apply_async((2,2), task_id=1, countdown=15)
myapp.tasks.add.apply_async((2,2), task_id=2, countdown=15)
它應該允許一個基於countdown=15
實例。 如果有另一個正在運行或等待的話,我怎么能完成第二個調用從不執行它?
接受的答案的一個問題是它很慢。 檢查任務是否已在運行涉及調用代理,然后迭代運行和活動任務。 如果您想快速排隊任務,這將無法正常工作。 此外,當前解決方案具有較小的競爭條件,因為2個進程可以檢查任務是否已經排隊等同(發現它不是),這將排隊2個任務。
更好的解決方案是我稱之為去抖動的任務。 基本上,每次排隊任務時都會增加一個計數器。 當任務開始時,你減少它。 使用redis然后它都是原子的。
例如
排隊任務:
conn = get_redis()
conn.incr(key)
task.apply_async(args=args, kwargs=kwargs, countdown=countdown)
然后在任務中,您有2個選項,是否要在第一個排隊(節流)后15秒執行任務,或者在最后一個排隊后15秒執行任務(去抖動)。 也就是說,如果我們繼續嘗試運行相同的任務,我們是否延長了計時器,或者我們只是等待第一個計時器15並忽略排隊的其他任務。
容易支持兩者,這里是debounce,我們等到任務停止排隊:
conn = get_redis()
counter = conn.decr(key)
if counter > 0:
# task is queued
return
# continue on to rest of task
油門版本:
counter = conn.getset(key, '0')
if counter == '0':
# we already ran so ignore all the tasks that were queued since
return
# continue on to task
該解決方案相對於接受的另一個好處是,密鑰完全在您的控制之下。 因此,如果您希望執行相同的任務,但僅針對不同的ID /對象執行一次,則將其合並到您的密鑰中。
更新
考慮到這一點,你可以更輕松地完成油門版本,而無需排隊任務。
節流v2(排隊任務時)
conn = get_redis()
counter = conn.incr(key)
if counter == 1:
# queue up the task only the first time
task.apply_async(args=args, kwargs=kwargs, countdown=countdown)
然后在任務中將計數器設置回0。
您甚至不必使用計數器,如果您有一個集合,您可以將密鑰添加到集合中。 如果你回到1,那么密鑰不在集合中,你應該排隊任務。 如果返回0,則密鑰已經在集合中,因此不要對任務進行排隊。
三思而后行! 在排隊任務之前,您可以檢查是否有任何正在運行/等待的任務。
from celery.task.control import inspect
def is_running_waiting(task_name):
"""
Check if a task is running or waiting.
"""
scheduled_tasks = inspect().scheduled().values()[0]
for task in scheduled_tasks:
if task['request']['name'] == task_name:
return True
running_tasks = inspect().active().values()[0]
for task in running_tasks:
if task['request']['name'] == task_name:
return True
現在,如果您排隊三個添加任務,第一個將排隊等待執行,剩下的不會排隊。
for i in range(3):
if not is_running_waiting('add'):
add.apply_async((2,2), countdown=15)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.