基于事件源的工作流模式


 本文档讨论了工作流模式,工作流模式提供了一种将长期运行的业务流程建模为步骤序列的方法。
本文还描述了工作流如何做出决策但并不实际执行决策,而是将执行委托给系统的其他部分。
维护工作流标识对于将事件关联回正确的工作流实例非常重要。
确定了实施工作流中的各种挑战,例如处理并发、超时、故障和补偿操作。

在过去的几个月里,我终于开始尝试基于事件的工作流,这是我过去几年一直在思考的话题。我从其他产品和项目中获得了灵感,如AWS Step Functions、GCP Workflows、Temporal、Camunda、NServiceBus和MassTransit等等。我想指出的是,如果你已经在其中任何一项上投入了大量资金,我并不是想阻止你使用它们。毕竟,一个简单的模式无法覆盖一个产品的广度。如果你正在应用事件源,那么下面的模式可能会被证明是一块有用的垫脚石。

为什么我决定爬这座山?好吧,一方面,我并没有被一些产品提供的工作流创作体验所淹没。诚然,这可能是一个争论点。另一方面,关于如何为事件源工作流建模的例子并不多。但更重要的是,这是一种瘙痒,早该抓挠了。

什么是工作流?
出于这篇博客文章的目的,我将把它定位为一个过程(或其一部分)的自动化,由于这样或那样的原因,我们无法在单个事务中完成。这些原因可能是技术性的,也可能是功能性的,或者两者兼而有之。

在这种情况下,工作流更类似于流程管理器,而不是saga,Saga意味着一个协调的中央单元。

根据我的经验,大多数工作流都可以建模为状态机或状态图。可视化这些状态机的能力反过来帮助我们看到更大的画面,并更容易地发现我们设计中的缺陷。

工作流放在哪里?
有时在的边缘,有时在服务或有界上下文或模块内部,但您对系统进行了分区。这也是为什么他们的编码形式可能只是我们试图自动化的整个过程的一小部分的原因。中央单位并不意味着自动集中整个过程。如果我们这样做,我们会陷入一个尴尬的境地,不知道该把它放在哪里。相反,多个工作流,每个工作流都在适当的位置,可以一起自动化整个过程,达到我们认为有用的程度。在边缘,他们可以观察外部和内部,并在它们之间进行调解,有时充当腐败的杀手,有时充当巴比伦的翻译。


工作流的目的是什么?
做出有助于推动整个过程的决策。每一个决策都会导致状态转换,这意味着它会从当前状态转换到下一个状态,即使该下一状态与当前状态相同。这是可以接受的,因为我们只明确那些与推动这一进程特别相关的国家。精心设计的工作流程有开始、中间和结束。除非它们真的很简单,否则建议放大工作流生命周期中的每个阶段。这意味着某种东西导致它们开始、继续存在和结束。在状态机中,我们将导致转换的事物称为触发器。毫不奇怪,消息是很好的触发候选者。

工作流如何实现?
我在现有实施中遇到的大多数工作流更像是谜语。它们隐藏在以 "Status "或 "State "为后缀的列或属性中,通常有 "Active"、"Inactive"、"Pending"、"InProgress "等值。

它们与其他布尔列和属性混合在一起,表明我们正处于机器的某种状态,也就是流程中的某个阶段。

这种实现方式听起来熟悉吗?我相信对你们中的一些人来说是的。

令我困惑的是,领域专家和他们的代理人对这种列式语言已经驾轻就熟。作为值使用的词语的含义必须反复解释,因为它们实际上是黄鼠狼之言。他们好像已经忘记了如何在不依赖当前解决方案的情况下阐明一个流程。

要我说,这就更需要把隐含的东西明确化。

说到实施工作流,有很多问题需要解决:

  • 如何启动工作流,如何知道要启动哪个工作流?
  • 如何将消息传递给工作流?
  • 信息如何与工作流程相关联?
  • 工作流需要记住什么,我们如何以及在哪里存储这些记忆,如何将这些记忆与工作流相关联?
  • 工作流如何以及何时执行决策?
  • 如何观察工作流的执行行为?

这份清单并不详尽,但已经涵盖了一些有趣的问题。这些问题中的大多数都可以被认为是通用的,也就是说,无论我们试图实现哪种工作流程,解决方案都是一样的。解决这些问题的组件通常都具有很高的可重用性,为解决这些问题而诞生的产品、库和框架也就不足为奇了。考虑到这一点,剩下的部分就是开发人员的编写体验了。

抽象地解释工作流是一回事,但将其与具体示例结合起来则更为有用。

更多点击标题