【问题标题】:viewflow.io: implementing a queue taskviewflow.io:实现队列任务
【发布时间】:2015-07-27 16:58:41
【问题描述】:

我想用ViewFlow library 实现以下用例:

问题

由用户启动的特定 Flow 的进程必须在队列中等待,然后才能执行 celery 作业。每个用户都有这些进程的队列。根据计划或手动触发,允许队列中的下一个进程继续进行。

示例

我的流程中的一个节点进入一个命名队列。应用程序中的其他逻辑为每个队列确定何时允许下一个任务继续进行。选择队列中的下一个任务并调用其激活的 done() 方法。

示例流程可能如下所示:

class MyFlow(Flow):

    start = flow.Start(...).Next(queue_wait)
    queue_wait = QueueWait("myQueue").Next(job)
    job = celery.Job(...).Next(end)
    end = flow.End()

问题

实现排队的最佳方法是什么?在上面的例子中,我不知道“QueueWait”应该是什么。

我已经阅读了文档和视图流代码,但我还不清楚这是否可以使用内置的 Node 和 Activation 类(例如 func.Function)来完成,或者我是否需要使用自定义类进行扩展.

【问题讨论】:

    标签: python django workflow django-viewflow


    【解决方案1】:

    经过大量实验,我得出了一个可行且简单的解决方案:

    from viewflow.flow import base
    from viewflow.flow.func import FuncActivation
    from viewflow.activation import STATUS
    
    
    class Queue(base.NextNodeMixin,
                base.UndoViewMixin,
                base.CancelViewMixin,
                base.DetailsViewMixin,
                base.Event):
    
        """
        Node that halts the flow and waits in a queue. To process the next waiting task
        call the dequeue method, optionally specifying the task owner.
    
        Example placing a job in a queue::
    
            class MyFlow(Flow):
                wait = Queue().Next(this.job)
                job = celery.Job(send_stuff).Next(this.end)
                end = flow.End()
    
            somewhere in the application code:
            MyFlow.wait.dequeue()
            or:
            MyFlow.wait.dequeue(process__myprocess__owner=user)
    
        Queues are logically separated by the task_type, so new queues defined in a
        subclass by overriding task_type attribute.
        """
    
        task_type = 'QUEUE'
        activation_cls = FuncActivation
    
        def __init__(self, **kwargs):
            super(Queue, self).__init__(**kwargs)
    
        def dequeue(self, **kwargs):
            """
            Process the next task in the queue by created date/time. kwargs is
            used to add task filter arguments, thereby effectively splitting the queue
            into subqueues. This could be used to implement per-user queues.
    
            Returns True if task was found and dequeued, False otherwise
            """
            filter_kwargs = {'flow_task_type': self.task_type, 'status': STATUS.NEW}
            if kwargs is not None:
                filter_kwargs.update(kwargs)
    
            task = self.flow_cls.task_cls.objects.filter(**filter_kwargs).order_by('created').first()
            if task is not None:
                lock = self.flow_cls.lock_impl(self.flow_cls.instance)
                with lock(self.flow_cls, task.process_id):
                    task = self.flow_cls.task_cls._default_manager.get(pk=task.pk)
                    activation = self.activation_cls()
                    activation.initialize(self, task)
                    activation.prepare()
                    activation.done()
                return True
    
            return False
    

    我试图使其尽可能通用,并支持多个命名队列以及子队列的定义,例如每个用户的队列。

    【讨论】:

    • 提供的队列节点只是结合了内置函数节点在流程实例查找中所做的事情。如果您可以在调用方位置进行流程实例查找,则可以改用 Function 节点。 github.com/viewflow/viewflow/blob/master/tests/integration/… 此外,如果您有可能并发流任务执行(拆分/加入),您应该在查询任务实例之前锁定流实例以避免竞争条件。 github.com/viewflow/viewflow/blob/master/viewflow/flow/…
    • 感谢@kmmbvnr,我已经按照您的建议更新了代码以使用锁定。通过您的解释,我可以看到如何使用 Function 节点执行相同的操作,但是 flow_func 代码似乎假定 task_loader 始终成功返回有效任务。因此,函数调用者不负责确保激活的任务存在吗?如果是这样,那么我的专用队列节点似乎更易于使用。
    猜你喜欢
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多