我有一个工作处理系统,其中每个工作包含数千个需要不同策略才能完成的任务。单个任务构成了整个工作。如果所有任务均已完成,则将作业标记为已成功完成,并执行其他步骤;如果任何任务失败,则必须将作业标记为已失败,并执行其他步骤(如果作业超时,则必须标记作业)失败并采取其他措施。
一旦收到作业的所有结果,就可以提取下一个作业。当前正在处理作业时,不应提取下一个作业。
这是流程的样子:
Job Polling Verticle将作业发布到事件总线,而Job Processing Verticle将每个任务发布到事件总线。作业策略完成后,它将任务结果发布到事件总线。
问题是我不知道确定该模型中所有任务何时完成的正确方法。所有的顶点都是无状态的,“作业处理顶点”不等待任何将来,即使“作业结果顶点”是有状态的,它也不知道应该期望多少结果。
我能想到的唯一方法是拥有一个全局有状态对象。但是我认为这不是一个好的设计。
此外,我需要知道作业何时超时。也就是说,它的运行时间比预期的要长,我需要考虑它的失败,记录并继续前进。
我可以使用全局状态来做到这一点,但我再次认为这不是正确的解决方案。
这种垂直图案对我想做的事情有意义吗?
答案 0 :(得分:3)
首先,让我尝试解决您的问题。然后,我将尝试解释该设计存在哪些问题。
问题是我不知道确定此模型中所有任务何时完成的正确方法。所有的顶点都是无状态的,“作业处理顶点”不等待任何将来,即使“作业结果顶点”是有状态的,它也不知道应该期望多少结果。
解决方案可以是参考计数顶点。每个工作程序在启动时应在事件总线上发出start message
,并在事件总线上发出jobId
,在完成时应发出end message
的{{1}}。即使您有扇出(那些情况是您不知道有多少工人),计数verticle也会知道这一点。在您的图表中,“作业后期处理顶点”是一个很好的选择。它可以维护一个计数器,只有当它达到零时,它才应该开始下一个作业。这也有助于避免实际共享一些内存引用。
此外,我需要知道作业何时超时。也就是说,它的运行时间比预期的要长,我需要考虑它的失败,记录并继续前进。
在相同的垂直版本中,每次获得新的jobId
时都可以启动一个计时器。如果得到start message
,请取消计时器。否则,取消当前作业,然后重新开始。
现在,此解决方案可以使用,但是设计存在两个主要缺陷。看来,事实之一是您将所有流量保持在内存中。如果您的应用程序崩溃,所有进度都将丢失,并且不清楚如何记录。也许轮询数据库中的end message
表实际上会更好,因为无论如何您的作业执行都是顺序的。
第二点是所有这些超时和引用计数都是结构化并发的自制实现。也许您应该为此考虑一下类似Kotlin的协程,它将为您解决许多问题。