工作流设计困难 - 状态机,是或不是

15
我是一个WF初学者,但我已经读了一本书并做了很多谷歌搜索。我想编写一个库存管理服务。库存由具有状态的单个项目组成:
1.备用 2.已安装 3.在维修中
项目可能在每个状态下花费几个月的时间,而且有数千个项目。
问题是,我是否要为所有不同状态创建状态机工作流程?还是为状态之间的转换创建工作流程?
如果我理解正确,如果我创建一个单一的状态机工作流,则每个项目始终会有一个正在运行的工作流。这意味着成千上万个永久运行的工作流。此外,我需要能够显示每个项目的状态快照,因此这意味着我必须以某种方式查询所有工作流程以获取它们当前所处的状态,或者在每个状态转换后以其他方式持久化到数据库中。
然而,状态机工作流逻辑上似乎是正确的选择,这就是我的困境所在。
如果您能帮助我,请告诉我:-)
谢谢!
更新:
假设我拥有比上述3个更多的状态,并且并非所有状态转换都是可能的。
赏金获得者:莫里斯 - 感谢其他每个人真正帮助我了解工作流程,MS工作流基础知识以及其他更轻量级的替代方案。不幸的是,只能有一个赏金获得者,Maurice的答案以及其评论对我帮助最大。

1
我不是工作流专家,但作为一名架构师,我会认真质疑您使用工作流引擎来建模库存项目状态的方法。或者我可能错过了什么。您用工作流程做什么? - TToni
工作流程的“核心”在于状态之间的转换,我需要验证我的业务逻辑。例如,在从“备用”到“已安装”的转换中,我需要先确保安装位置是空闲的,然后我必须更改状态,然后我必须通知物流部门进行安装等操作。 - Aviad P.
好的,所以当一个项目状态改变时,您需要执行一些业务逻辑。但我仍然不明白为什么您要使用WF来完成这个任务。我假设您无论如何都会将每个项目的当前状态存储在某个数据库中。如果您没有,并且有其他很好的理由使用WF,那么对于每个项目拥有一个WF实例看起来是更好的选择。但是,如果WF的状态转换只反映了项目状态转换,那么您最终只会以复杂的方式存储项目状态(作为持久化的WF实例而不是某个数据库列)。 - TToni
你说的有道理,但是你能想到什么可以使这种情况更适合状态机工作流的吗?此外,使用工作流(无论是状态机还是其他)本身就是一个好习惯,它使执行流程更加清晰。如果不使用状态机工作流,一些过程将在代码中变得模糊。这是我的困境之一。--- 晚安TToni :-) - Aviad P.
我仍然觉得WF实例不是捕获库存项目状态的正确工具。如果您想在WF中捕获非平凡逻辑以进行项目状态转换,那么可以使用不同的WF来处理每个转换,而不是一个包含库存项目状态的大型WF。您仍然可以使用流程模型图来解释整体逻辑,但不必在WF模型中捕获所有内容。如果有人遇到像您这样的问题,那么99/100次是使用组件的方式不正确的指示器。 - TToni
请再解释一遍最后那句话:“如果有人遇到了……”你的意思是什么?这个困境不常见吗?你能举个例子说明何时使用(持续)状态机工作流更正确吗?此外,您可能希望将我们所有的想法和结论汇总成一个实际的答案帖子…… - Aviad P.
9个回答

22

状态机是一种非常强大的技术实现方式,虽然我建议您考虑一个叫做StateLess by Nicholas Blumhardt (Autofaq creator)的框架,因为它是一种非常简单的状态机实现,避免了Windows Workflow不必要的复杂性。他的方法避免了长时间运行的工作流被运行时引擎占用的问题,因为状态由简单的变量(如字符串或整数)定义。

这是一个示例状态机:

var phoneCall = new StateMachine<State, Trigger>(State.OffHook);

phoneCall.Configure(State.OffHook)
    .Permit(Trigger.CallDialed, State.Ringing);

phoneCall.Configure(State.Ringing)
    .Permit(Trigger.HungUp, State.OffHook)
    .Permit(Trigger.CallConnected, State.Connected);

phoneCall.Configure(State.Connected)
    .OnEntry(() => StartCallTimer())
    .OnExit(() => StopCallTimer())
    .Permit(Trigger.LeftMessage, State.OffHook)
    .Permit(Trigger.HungUp, State.OffHook)
    .Permit(Trigger.PlacedOnHold, State.OnHold);

// ...

phoneCall.Fire(Trigger.CallDialled);
Assert.AreEqual(State.Ringing, phoneCall.State);

您的状态可以是一个整数,这将允许您从数据库中获取当前状态。可以在状态机的构造函数中设置如下:

var stateMachine = new StateMachine<State, Trigger>(
    () => myState.Value,
    s => myState.Value = s);

相对于运行Windows Workflow所需的多个项目,您只需要一个程序集即可实现此功能。维护成本极低,没有“设计者”为您生成代码等。再次强调,它很简单,这就是其美妙之处。


9

首先,您是否确定需要一个工作流程。

工作流程是一种业务流程。这意味着该流程具有开始和结束的阶段。根据您的描述,似乎更像是跟踪某种库存物品。

当物品状态发生变化时,工作流程会更为合适。例如,当某个物品被安装后出现故障并需要修理时,您可以启动工作流程来获取备件、将损坏的零件送修,并在最终将其作为修复后的备件返回到仓库中。工作流程将描述此过程,并从报告物品损坏开始,以修复或丢弃并替换物品结束。

此最后一个工作流程也可以是状态工作流程,因为物品经历了各种阶段,如:

  • 已损坏并安装
  • 已损坏并更换
  • 在店内维修
  • 已修复
  • 等等

一个工作流程不一定要有终点。当然,这只是理论上的说法。例如,即使项目最终可能被放入回收站,它们仍然可以被恢复,对于项目来说没有最终状态,除非完全瓦解。此外,我当然会使用工作流程来进行状态转换,这是必须的,无论我是否还包括状态机。 - Aviad P.
我认为无尽工作流的潜在问题是,如果您想更改业务逻辑,则必须在原地更新对象。如果更改工作流程,可能会影响诸如持久化工作流程的数据库模式之类的事情,这可能会变得棘手。Maurice的答案听起来像是尝试避免这个问题的好方法。 - Tim Lovell-Smith
+1. 工作流基础仅不是问题定义中合适的技术。@Aviad: 是的,“理论上”工作流程不需要结束。然而,WF比理论工作流程有更具体的目标。它特别针对有逻辑终点的业务流程。它旨在建模正在进行中的任务。它肯定不是设计用于处理数千个非常长时间运行的工作流程。 - AnthonyWJones
@Aviad:你说得对,工作流程永远不需要结束。没有程序必须结束,但大多数都会以很好的理由结束,因为几乎没有什么需要永远持续下去。创建一个始终运行的工作流程很容易,并且通过持久性甚至可能不需要太多资源。然而,程序往往会失败,因此您需要其他东西来确保没有工作流程被忽略。这是另一个程序。将数据保存在数据库中,并在发生某些情况时启动工作流程更加合适和安全。 - Maurice

2

鉴于您的增加(超过3个状态,不允许所有转换),我会执行以下操作:

  1. 将每个项目的状态存储在项目本身中。
    这可以非常容易地实现:像其他人在帖子/评论中提到的那样,向类添加成员或向表添加列。
  2. 使用一个状态机(可以是任何东西,从类的实例到具有合法转换的表),它保存您的业务逻辑,即状态之间允许的转换和更改项目状态时执行的其他操作的知识。

然后,只需要当外部事件发生时强制/暗示时,使用状态机转换您的项目。


我同意。您可以使用接口和依赖注入技术使模型更加灵活。 - Brandon Montgomery
这是指实际的.NET工作流基础吗?还是你在谈论单词“workflow”的英语字典含义?我只对前者感兴趣,而看起来似乎是后者... - Aviad P.
哦,对不起Aviad。您没有明确提到.NET工作流基础,所以我认为您是在询问实现项目的一般方法。 - Dave O.

2

好的。让我们看看我能否帮助您。让我们从设计开始:

设计状态机和工作流程都是有意义的。它们只是您问题的不同视角,并从不同的角度为其提供了一些启示。实际上,经常发生新接触工作流的开发人员设计状态机而不是工作流程的情况。工作流程主要是在图表中切换盒子和转换的角色:盒子是可以更改状态的活动 - 在转换中,工作项可以进入新状态(好吧,这不科学正确,但可能会有所帮助)。

对我来说,状态机方面似乎更重要。因此,请将软件实现为状态机。

是的 - 您应该在数据库中使所有项目持久化。这也是如何保持非常长时间运行的工作流程正常运行的方法 - 它们在数据库中存活,直到通过任何活动重新激活。这是所有现成的业务流程管理系统(BPMS)的运作方式。这些工作流程不保留在内存中。

将所有内容保存在数据库中将使创建报告变得容易。

如其他人已经提到的,创建一个包含状态信息的新列或甚至创建一个包含元数据的新表:状态、状态更改的日志、更改状态的人员、有关即将到来的事件的信息(已订购但未交付的零件-在多少天后应该与供应商核对交货是否丢失?)。这将为您提供根据需要添加元数据的机会,而不影响您的零件数据库。

希望这可以帮助您!


我想就使用.NET工作流基础(.NET Workflow Foundation)进行具体说明。您是否建议我仅使用状态机工作流,当然还包括状态转换工作流,但对于这些项目(包括它们的状态),我使用自己的持久化?此外,我从未打算让工作流保留在内存中,当然它们将使用工作流持久化服务进行持久化,但是SqlPersistenceService所持久化的形式对我来说是不透明的,我无法查询它或执行任何操作,除了重新加载工作流程。但是,它们永远不会达到最终状态 - 这就是我的意思。 - Aviad P.
我还没有使用过.NET工作流基础,我想我也永远不会了。我正在放弃另一个工作流解决方案,因为其中太多的东西对我来说是不透明的。通常你可以看到解决方案,但框架却不允许你实现它。但这是另一个话题了。当你使用一个框架时,尽量遵循它的规则。按照框架建议的方式实现你的流程/工作流/状态机,否则会引起问题。如果工作流基础引起了太多问题,也许它并不是你的应用程序的正确框架? - rdmueller
顺便说一句:一个永远不会达到最终状态的工作流对于工作流引擎来说不应该是一个问题。我猜限制更多的是活动工作流的数量,在你的情况下似乎相当静态... - rdmueller

1

正如在原帖的评论中所讨论的那样,我对于在这个特定问题上使用 WF 存在一些问题。

这句话 "物品可能在每个状态中停留数月,而且有数千个物品" 是触发这个问题的原因:我认为工作流程(使用 WF 建模)应该是短命的。虽然没有硬性规定 WF 实例可以或应该存活多长时间,但是几个月甚至几年的生命周期会在我这里触发一种“越界”异常,尤其是当这成为数千个项目非常普遍的情况时 :-)

您在评论中使用 WF 的理由是正确的,但并不解决这个特定问题。因此,我建议您使用短命、专门的 WF 模型来处理库存商品状态之间发生的事情,但是不要在 WF 状态中捕获商品状态本身。长周期、很少更改的状态更适合数据库引擎,人们期望它们在那里,并且易于报告。


感谢您的所有建议TToni,我仍然不相信没有永久(状态机)工作流程的地方。理论上是这样说的,实现肯定支持这一点。但是,我发现很难忽略状态机工作流程会对我的应用程序造成的所有阻碍...困境仍然存在 :-) - Aviad P.
那就是我所说的。如果你想使用某种工具,但找不到简单直接的方法让它为你工作,那么你可能使用了错误的工具。或者你手头有一个非常困难或创新性的问题(这似乎不是这种情况)。无论如何,祝你好运。我现在要离线一段时间了。 - TToni

0

尽管状态机模式在技术上是正确的选择,但也有一种选项可以创建一个带有一个巨大循环的顺序工作流。在某些情况下,它实际上运行得更好,并且更易于理解。


1
不解决我的困境 - 我是为每个项目创建一个持续运行的工作流(即状态机工作流),还是仅在状态转换之间使用顺序工作流。 - Aviad P.

0

你有三种不同的状态,就我所见,所有的转换都是允许的。鉴于此,我不会费心去考虑状态机,也就是一段检查允许转换并进行前进移动的代码。

当状态驱动业务或需要一个可信赖的单一代码片段负责“经过验证的转换”时,状态机才有意义。

更简单地说,你只需要在任何时候拥有给定状态的实体...


假设我有更多的状态,并且并非所有的转换都是允许的... 我会更新我的问题。 - Aviad P.

0

Aviad,我同意你的评论,即工作流应该处于状态之间。被盘点零件的状态听起来像是物品的状态/属性。该状态可以以几乎任何方式存储(例如数据库、文件...),因为物品在状态之间移动将存在于业务逻辑层中。

听起来是个有趣的项目,祝好运。


0

我认为我们需要在这里理解几件事情。

状态机 - 重点是表示实体所处的特定状态。

工作流 - 将定义您遵循的过程,以将实体从初始状态移动到最终状态。

在您的情况下,由于您的整个流程围绕单个实体展开,并且其在任何给定时间点的当前状态都是单例的,因此我建议选择状态机。

建议: Apache Commons SCXML提供了一个轻量级、可嵌入的状态机引擎,可以在应用程序中运行时轻松配置和自定义。

关键点在于您必须以这样的方式定义您的scxml,以便在实体的状态转换之间 - 您可以使用“操作”或“监听器”指定要执行的工作流。

示例程序: https://www.javacodegeeks.com/2012/06/apache-commons-scxml-finite-state.html

关于Commons SCXML 2.0的更多信息https://events.linuxfoundation.org/sites/events/files/slides/ApacheConUS2014%20-%20Apache%20Commons%20SCXML%202.0.pdf


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接