簡體   English   中英

django-channels/celery:如何跟蹤任務列表的進度?

[英]django-channels/celery: how to track progress of a list of tasks?

我“成功地”從視圖向客戶端發送了一條消息,其中包含一組任務(不是實際的芹菜組)的狀態。 問題是:這真的忽略了是否所有任務都實際執行了。 我試圖添加一個回調( task.apply_async(link=) ),但這也沒有幫助。

任務本身並不會花費很多時間,但我真的希望能夠在實際執行任務時增加計數器:

if 'selected' in request.GET:
        selected_as_list = request.GET.getlist('selected')
        print(selected_as_list)
        searches = list(set([s.strip() for s in selected_as_list if s.strip()]))
        task_group = [refresh_func.s(str(user_profile.id), search, dont_auto_add=True) for search in searches]

        for i,task in enumerate(task_group):
            task.apply_async()
            Group(str(request.user.id)).send({"text": json.dumps({"tasks_completed": i+1,
                                                                  "task_id": "fb_import",
                                                                  "completed": True if i == len(task_group) -1 else False,
"total": len(task_group)})})

所以我將代碼移出視圖,並移到實際調用要完成的操作的同一個塊中。 雖然這意味着我現在傳遞了許多參數,但這解決了最初的問題。 但它提出了另一個問題:索引為“1”的任務可以在索引為“3”的任務之后完成,這顯然會錯誤地更新計數器。

可以做些什么來解決這個問題?

如何生成一個后台線程來定期檢查生成的任務的狀態(如果您知道任務的 ID,就可以獲得這些狀態)?

該線程應該在 Django 服務器中運行(而不是在 Celery 任務中),因為這可能是您的django-channel處於活動狀態的地方:如果您在任務中調用Group(...).send ,它可能無法訪問它(特別是因為通常芹菜工人在不同的進程/機器中運行)

假設您在視圖的.GET實現中生成任務。 也許您可以在那里收集任務 ID(它們產生的地方)並定期檢查它們在線程中的狀態(這樣您就不會阻止.GET響應)。

假設您生成任務的視圖如下所示:

class Test(generic.TemplateView):
    template_name = 'stack_092.html'

    def get(self, request, *args, **kwargs):
        logger.info("Yep")
        task_group = [foo_task.s(i) for i in range(5)]
        logger.info("Task signatures created: %s", task_group)

        task_ids = [task.apply_async().task_id for task in task_group]
        logger.info("Tasks launched")
        th = threading.Thread(target=verify_task_ids, args=('request.user.id', task_ids))
        th.start()
        logger.info("Thread started")
        return super(Test, self).get(request, *args, **kwargs)

像這樣的東西可能是線程的verify_task_ids目標函數:

def verify_task_ids(channel_group_id, task_ids):
    previous_finished_task_ids = set()
    finished_task_ids = set()
    logger.info("Verifying %s task_ids", len(task_ids))
    while len(finished_task_ids) < len(task_ids):
        finished_task_ids = set()
        for task_id in task_ids:
            if AsyncResult(task_id).ready():
                finished_task_ids.add(task_id)
        if finished_task_ids != previous_finished_task_ids:
            logger.info("%s new finished tasks", 
                        len(finished_task_ids) - len(previous_finished_task_ids))
        previous_finished_task_ids = finished_task_ids

在示例中, channel_group_id參數只是一個純硬編碼字符串"request.user.id" 在您的情況下,您應該用登錄服務器的用戶的實際request.user.id替換它,因為這是您的組 ID。

你會看到,當一個新任務完成時,我只顯示一條日志消息:

if finished_task_ids != previous_finished_task_ids:
        logger.info("%s new finished tasks", 
                    len(finished_task_ids) - len(previous_finished_task_ids))

這是您應該調用的而不是logger.info函數的地方

if finished_task_ids != previous_finished_task_ids:
    Group(
        str(channel_group_id)
    ).send(
        {
            "text": json.dumps({
                "tasks_completed": len(finished_task_ids),
                "task_id": "fb_import",
                "completed": len(finished_task_ids) == len(task_ids),
             })
         }
     )

我不太了解(呃......任何東西,而是......關於django-channels)所以我不確定這個解決方案是否有效,但也許值得一試?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM