onlab/balno-workflow

此包的最新版本(1.1.1)没有可用的许可信息。

PHP 5.5+ 并行执行工作流

1.1.1 2015-09-25 10:21 UTC

This package is not auto-updated.

Last update: 2024-09-28 17:17:53 UTC


README

Build Status

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将准备产品工厂的订单。向客户发送邮件将比向工厂创建订单更好。因此,在这种情况下,为了满足客户,最好首先执行最慢的流程。

如果您真的需要并行执行,您可以设置一个初始状态,没有默认转换,暂停一个或两个工作流程,然后以某种工作方式运行每个工作流程。

重要:当您恢复子工作流程并完成时,工作流程将自动尝试恢复父上下文。因此,如果您真的试图并行化这些子工作流程,请确保您的锁定系统与这种情况兼容。