How to implement long running flows, sagas, business processes or similar

时间:2022-08-27 10:03:26

转自:https://blog.bernd-ruecker.com/how-to-implement-long-running-flows-sagas-business-processes-or-similar-3c870a1b95a8

Long running flows can span from a few milliseconds up to several months or years (see What are long running processes? for details). Note that after some discussions I switched my wording from “long running processes” to “long running flows”.

When implementing these flows within your business application (or microservice architecture) you have to think about certain requirements, especially state handling and subsequent challenges like monitoring and versioning. Visualization of flows might come in handy. How can you tackle these requirements? I want to discuss the basic alternatives in this article:

  • Storing state in domain entities
  • Storing state in separate state entities
  • Using a state machine
  • Using a routing slip to avoid any central state

Storing state in domain entities

The simplest option to get started is to add some state information to already existing entities. Think of a simple order application, then it might look like this:

class Order {

String id;

Customer customer;

List<OrderItem> items;

static enum GoodsDeliveryStatus {

NOTHING_DONE,

GOODS_RESERVED,

GOODS_PICKED

}

boolean paymentReceived = false;

GoodsDeliveryStatus deliveryStatus = GoodsDeliveryStatus.NOTHING_DONE;

boolean shipped = false;

//...

}

Advantages:

  • Easy to setup
  • Easy to query for state and entity information (“all orders containing blue umbrellas for male customers, which are payed but not yet delivered”). This also holds true for reporting.

Disadvantages:

  • State handling is hard coded. It is not easy to understand when and why state changes are triggered, which makes changing the flow hard.
  • All subsequent requirements have to be self-coded. If you need monitoring for stuck processes or timeouts/escalations to happen, you need to do it yourself. Another big topic for you to solve is versioning of the flow because whenever changing the flow you will have entities in some intermediary state to handle.

Once bitten, twice shy! Hence I am personally not a fan of this alternative, as I have seen it too often growing uncontrollably into a home-grown state machine (I have described this in the 7 sins of workflow).

However, if your requirements are simple enough, and you are sure it will stay like this for a while, you can go down this route. Just be honest with yourself — don’t do it just because you have a bad feeling about existing tools without concrete reasons. You may have based this on misconceptions which I plan to describe to you below. Sorry — once bitten…

Storing state in separate state entities

A somehow similar concept is to store the state in entities but separated from your core domain entities. So you could have the following entity for the order:

class OrderSaga {

String orderId;

static enum GoodsDeliveryStatus {

NOTHING_DONE,

GOODS_RESERVED,

GOODS_PICKED

}

boolean paymentReceived = false;

GoodsDeliveryStatus deliveryStatus = GoodsDeliveryStatus.NOTHING_DONE;

boolean shipped = false;

}

This alternative has the advantage that the state is now clearly separated from your core domain entities, keeping the concepts pretty clear. And it does not introduce big downsides, all other forces are comparable to saving the state in the domain entities.

Using a state machine

You can leverage existing state machines, often named workflow engine, process engine, orchestration engine or the like. Using for example the open source Camunda library you could express the flow like this:

private void createFlow() {

engine.getRepositoryService().createDeployment()

.addModelInstance(Bpmn.createExecutableProcess("order")

.startEvent()

.serviceTask().name("Retrieve payment").camundaClass(DoPaymentAdapter.class)

.serviceTask().name("Fetch goods").camundaClass(PickGoodsAdapter.class)

.serviceTask().name("Ship goods").camundaClass(ShipGoodsAdapter.class)

.endEvent().camundaExecutionListenerClass("end", OrderCompletedAdapter.class)

.done()

).deploy();

}

As you can see there are some classes containing logic attached. Afterwards this flow can be executed on the engine directly. The engine will take care of state handling and can even visualize the flow graphically, e.g. for later monitoring (as it also records a lot of audit data):

How to implement long running flows, sagas, business processes or similar

You could also use a graphical modeler to create the flow which is especially helpful if the flow gets more complex than our simple example. The good thing is: it is totally up to you to decide if you want to use code or graphics. Either way you can leverage visualization at least in operation.

The graphical flow looks like this, Camunda uses the ISO standard BPMN for modeling and visualization:

How to implement long running flows, sagas, business processes or similar

Advantages:

  • The engine does all state handling and provides the required features for long running flows (monitoring, timers, versioning, …).
  • You gain visibility of the flow which might be interesting during requirements engineering (how to implement this?), development (what do I have to implement right here?) and operations (is everything running smooth? where exactly do we have problems?). Recommended read: BizDevOps — the true value proposition of workflow engines
  • You also get additional tools for advanced use cases. As an operator you could for example adjust the state for a certain flow in case of errors.

Disadvantages:

  • You introduce a new component to your stack.
  • A lot of state machine vendors still follow a “zero-code idea” (also described in the 7 sins of workflow) typically leading to inflexible architectures and frustrated developers. So you have to be careful to pick the right tool.
  • Many people think about enterprise wide central BPM approaches when saying “BPMN”. Doing so might end up in a BPM monolith (see the 7 sins of workflow). So you have to apply the tool right.

Rejecting state machines or appropriate engines is often done as a result of misconceptions — what a bummer! When selecting the right product and applying it properly later on, you can leverage the advantages without realizing the risks mentioned.

The state machine market is cluttered making the process of product selection challenging. Quick research reveals already 5 market categories:

To make the decision possible, you must first think about your use case. The order example in this post is best solved with a tool from the first category because you can easily leverage a lightweight engine but do complex flows with it. Additionally that provides you with a lot of additional features like visualization.

Sample code for the order process using Camunda is part of the flowing retail example.

No central state, but a routing slip

I recently had an interesting discussion about using Routing Slips. I want to include it in this post as the pattern is relatively unknown but could also provide a solution.

Let’s assume our order process is handled by multiple microservices which communicate via messages or events. You can see this in action in the flowing retail example. Using a routing slip, the steps to process an order are:

  • Process event “order created” by a very thin order service and create the proper routing slip for this order (e.g. “do payment”, “pick goods” and “ship goods” — the commands from the flowing retail example). Now pass the event onto the bus.
  • A thin layer between the event bus and the client can read the routing slip so the payment service will recognize it is next in the routing slip and do the payment. It marks the “do payment” as done or removes it from the slip.
  • The payment sends the “payment received” event including the routing slip and inventory recognizes it is next on the routing slip. The big difference now is: There was no central component required to say what is next, everything was written in the routing slip at the beginning!
  • And so on.

Advantages:

  • No central state handling required

Disadvantages:

  • Hard to investigate the current order state as you have to find the latest version of the routing slip. This might be solved by some CQRS query component investigating all routing slips and gather information.
  • No easy way of changing the route when the message is on its way.
  • I do not know any out-of-the-box components solving this so it always involves coding

So far, I have not found a very good reason to prefer the routing slip over the engine approach for the kind of flow shown in this example but I hope this post might trigger some discussions or comments.

Conclusion

There are different approaches to handle the state for long running flows. When researching on the web you get the impression that only state in entities is really known, especially if you face Microservices or Sagas (from the Domain Driven Design Community).

Personally, I think the state machine approach is most often better suited which is not that surprising: You have state, use a state machine. But in the past most existing tools were too complicated and scared developers away. That was the reason why we created the open source platform Camunda in the first place. And it has really changed in the recent years, there are now lightweight engines available which deserve a honest look at.

As for the question what approach to use: as always — it depends.

 
 
 
 

How to implement long running flows, sagas, business processes or similar的更多相关文章

  1. How to&colon; Debug X&plus;&plus; Code Running in &period;NET Business Connector &lbrack;AX 2012&rsqb;

    This topic has not yet been rated - Rate this topic  http://msdn.microsoft.com/EN-US/library/bb19006 ...

  2. Building Applications with Force&period;com and VisualForce&lpar;Dev401&rpar;&lpar;十&rpar;&colon;Designing Applications for Multiple Users&colon; Building Business Processes that You Want

    Dev401-011: Building Business Processes that You Want Course Objectives1.Describe the capabilities o ...

  3. Building Applications with Force&period;com and VisualForce&lpar;Dev401&rpar;&lpar;十二&rpar;&colon;Implementing Business Processes&colon;Automating Business Processes Part 1

    ev401-013:Implementing Business Processes:Automating Business Processes Part 1 Module Objectives1.Li ...

  4. Building Applications with Force&period;com and VisualForce&lpar;Dev401&rpar;&lpar;十四&rpar;&colon;Implementing Business Processes&colon;Auditing Processes

    Dev401-015:Implementing Business Processes:Auditing Processes Module Objectives1.list some of the fe ...

  5. Building Applications with Force&period;com and VisualForce&lpar;Dev401&rpar;&lpar;十三&rpar;&colon;Implementing Business Processes&colon;Automating Business Processes Part II

    ev401-014:Implementing Business Processes:Automating Business Processes Part II Module Agenda1.Multi ...

  6. Why service collaboration needs choreography AND orchestration

    转自:https://blog.bernd-ruecker.com/why-service-collaboration-needs-choreography-and-orchestration-239 ...

  7. Dynamic CRM 2013学习笔记(三十九)流程2 - 业务流程(Business Process Flows)用法详解

    业务流程(Business Process Flows)是CRM 2013 里一个新的流程,它提供了可视化的流程表现.业务人员创建有效.流线型的业务流程让最终用户知道当前在哪.下一步要做什么,用户可以 ...

  8. Tips for Planning Your Business Startup

    原文链接:http://domaintree.me/?p=1037 By Robert Thibodeau –  Starting a business can be a very daunting ...

  9. Ultimate Facebook Messenger for Business Guide &lpar;Feb 2019&rpar;

    Ultimate Facebook Messenger for Business Guide (Updated: Feb 2019) By Iaroslav Kudritskiy November 2 ...

随机推荐

  1. mysql数据库表的自增主键号不规律,重新排列

    mysql数据库表的自增主键ID乱了,需要重新排序. 原理:删除原有的自增ID,重新建立新的自增ID. 1.删除原有主键: ALTER TABLE `table_name` DROP `id`; 2. ...

  2. 关于mybatis一对多关联时

    一对多关联时注:collection标签,property属性名称,column参数字段, ofType查询返回类型,select查询方法,javaType方法的返回类型

  3. windows namedPipe 命名管道clent and server

    1.client: #include "iostream" #include "windows.h" using namespace std; void mai ...

  4. ubuntu下查看cpu信息

    查看CPU信息cat /proc/cpuinfo 几个cpu more /proc/cpuinfo |grep "physical id"|uniq|wc -l 每个cpu是几核( ...

  5. HDU-3308 LCIS(区间合并)

    题目大意:给一个整数序列,m次询问,每次询问某个区间中最长连续上升子序列的长度. 题目分析:线段树区间合并.维护以区间左端开头的.以区间右端点结尾的和区间最长的上升连续序列. 代码如下: # incl ...

  6. ASP&period;NET Web - 服务器控件

    控件 HTML 说明 Label <span> 返回一个包含文本的span元素 Literal static text 返回简单的静态文本.使用Literal控件,可以根据客户应用程序转换 ...

  7. 简述iproute家族命令

    ifconfig 是用来查看.配置.启用或禁用网络接口的工具.可以用这个工具来临时配置网卡的IP地址.掩码.广播地址.网关等. 语法 ifconfig [interface] 参数 up 启动指定网络 ...

  8. Android Studio 第一次启动配置

    第一次启动AS前,为了避免重新下载新版本的SDK 操作如下: AS启动前,请先将bin目录的idea.properties文件中增加一行:disable.android.first.run=true ...

  9. dos命令行运行&period;class源文件错误解决办法

    dos命令行运行java源文件 public static void main(String[] args) throws IOException { // TODO Auto-generated m ...

  10. Windows 一键安装 Redmine 部署及配置

    Redmine的主要功能包括 添加和跟踪问题(或让您的团队完成). 使用Redmine内置的甘特图和日历计划和管理您的项目. 使用项目wiki和文档管理器来存储项目文档. 配置通知以保持有关问题状态和 ...