onlab / balno-workflow
PHP 5.5+ 并行执行工作流
Requires
- php: >=5.5
- symfony/event-dispatcher: ^2.6
Requires (Dev)
- phpunit/phpunit: ~4.6
This package is not auto-updated.
Last update: 2024-09-28 17:17:53 UTC
README
BalnoWorkflow 是一个针对 PHP 5.5+ 开发的工作流引擎,基于一些其他工作流和状态机,它不包含所有功能在同一库中。
此工作流为您提供以下功能
- 根据 SCXML (http://www.w3.org/TR/scxml) 结构设置工作流的简洁语法。
- 易于设置并行工作流(分支/合并)。
- 暂停的工作流可以通过事件触发器继续。
- 当满足守卫条件(如果已设置)时,基于事件的自 Transition 不自动运行。
- 使用 Pimple 作为 DI 容器,将守卫和动作配置为服务。
- 可用事件以锁定控制、记录或其他您想通过事件监听器实现的内容。
可订阅的工作流事件
您可以在 接口 WorkflowEvents
中检查可用的事件
- begin_execution:当工作流执行开始时触发。
- end_execution:当工作流执行完成(暂停或完成)时触发。
- start_transition:在更改工作流状态时,在 onExit 动作之前触发。
- state_changed:在 onExit 和 onEntry 动作之间,在上下文中设置当前状态后触发。
- end_transition:在更改工作流当前状态时,在 onEntry 动作之后触发。
基本定义示例
以下情况中,始终将第一个定义的状态设置为初始状态,'state_1' 状态被设置为初始状态。
use BalnoWorkflow\DefinitionsContainer; $definitionsContainer = new DefinitionsContainer(); $definitionsContainer->addDefinition('sample_workflow', [ 'state_1' => [ targets => [ 'state_2' => null, ], onExit => [ [ action => 'pimple_service:method1' ], ], ], 'state_2' => [ targets => [ 'state_3' => [ event => 'some_event' ], 'state_5' => [ guard => 'balno.workflow.guard.timer:hasTimedOut("30m")' ], ], onEntry => [ [ action => 'pimple_service1:method' ], [ action => 'pimple_service2:method' ], ], ], 'state_3' => [ targets => [ 'state_4' => null, ], parallel => [ 'forked_workflow1', 'forked_workflow2', ], ], 'state_4' => [ onEntry => [ [ action => 'pimple_service:method2("param")' ], ], ], 'state_5' => null ]); $definitionsContainer->addDefinition('forked_workflow1', [ ... ]); $definitionsContainer->addDefinition('forked_workflow2', [ ... ]);
给定一个新的 Context
以执行...
use BalnoWorkflow\Workflow; use BalnoWorkflow\Context; $context = new Context(); $workflow = new Workflow(...); $workflow->execute($context);
... 此工作流将执行以下历史记录
触发
begin_execution
监听器重要:初始状态不会触发 onEntry 动作
... 检查默认(未设置事件)的 transitions(找到无守卫到 state_2 的 transition)
触发
begin_transition
监听器执行 state_1 的
onExit
动作触发
state_changed
监听器执行 state_2 的
onEntry
动作触发
end_transition
监听器... 检查默认 transitions(找到具有守卫的一个)
执行 守卫
balno.workflow.guard.timer:hasTimedOut("30m")
返回false
触发
end_execution
监听器
现在状态处于暂停状态。要继续工作流,必须在 30m(以满足配置的守卫超时)之后执行工作流,或者使用事件 some_event
执行。
要触发事件,必须运行以下代码(假设您正在使用持久化的上下文恢复工作流)
$context = $myContextService->getSubjectWorkflowContext($subject);
$workflow->execute($context, 'some_event');
.. 或者如果您只想使工作流继续以达到超时条件
$context = $myContextService->getSubjectWorkflowContext($subject);
$workflow->execute($context);
动作
每个动作或守卫都通过工作流执行,将 Context
对象作为第一个参数传递,然后是动作或守卫上配置的参数。
给定一个守卫 guard.example:someGuardCondition("test1", 2)
,方法必须类似于以下
class GuardExample
{
public function someGuardCondition(ContextInterface $context, $parameter1, $parameter2)
{
...
}
}
并行执行
并行执行是一种特殊状态,无法转发到另一个状态(甚至通过事件),直到所有并行工作流都完成。
从[基本定义示例]
state_3
|
|------------v--------------------v
| | |
| forked_workflow1 forked_workflow2
| | |
|------------^--------------------^
|
state_4
由于PHP默认不支持线程,BalnoWorkflow将首先执行forked_workflow1
,然后执行forked_workflow2
。因此,我建议首先放置快速进程,然后是慢速进程。
但想象一下,你需要向客户发送一封确认邮件(你使用的是慢速SMTP服务器)在forked_workflow2
中,而forked_workflow1
将准备产品工厂的订单。向客户发送邮件将比向工厂创建订单更好。因此,在这种情况下,为了满足客户,最好首先执行最慢的流程。
如果您真的需要并行执行,您可以设置一个初始状态,没有默认转换,暂停一个或两个工作流程,然后以某种工作方式运行每个工作流程。
重要:当您恢复子工作流程并完成时,工作流程将自动尝试恢复父上下文。因此,如果您真的试图并行化这些子工作流程,请确保您的锁定系统与这种情况兼容。