跳转到正文

工作流补偿

补偿机制允许你为已完成的工作流步骤添加回滚处理程序。Queuety 会在该步骤完成时存储公开状态快照,然后在工作流取消时运行补偿处理程序,并可选择在工作流失败时运行。

compensate_with() 方法

应撤销某个步骤时,请紧接着该步骤调用 compensate_with():

PHP
use Queuety\Queuety;

Queuety::workflow( 'provision_account' )
    ->then( CreateRemoteUserStep::class )
    ->compensate_with( DeleteRemoteUserCompensation::class )
    ->then( CreateSubscriptionStep::class )
    ->compensate_with( CancelSubscriptionCompensation::class )
    ->then( SendWelcomeEmailStep::class )
    ->dispatch( [ 'user_id' => 42 ] );

如果工作流之后被取消,Queuety 会运行:

  1. CancelSubscriptionCompensation
  2. DeleteRemoteUserCompensation

补偿处理程序

补偿处理程序实现 Contracts\Compensation:

PHP
use Queuety\Contracts\Compensation;

final class DeleteRemoteUserCompensation implements Compensation {
    public function handle( array $state ): void {
        remote_api_delete_user( $state['remote_user_id'] );
    }
}

处理程序接收的是被补偿步骤完成后立即保存的公开工作流状态。不会包含保留的内部键。

取消与失败

显式取消时,已完成步骤的补偿处理程序始终会在可选的 on_cancel() 处理程序之前运行。

失败时,只有选择启用后才会运行补偿处理程序:

PHP
Queuety::workflow( 'provision_account' )
    ->then( CreateRemoteUserStep::class )
    ->compensate_with( DeleteRemoteUserCompensation::class )
    ->then( CreateSubscriptionStep::class )
    ->compensate_with( CancelSubscriptionCompensation::class )
    ->then( ChargeCardStep::class )
    ->compensate_on_failure()
    ->dispatch( $payload );

如果没有 compensate_on_failure(),失败的工作流会保留已完成步骤的历史记录,并可从失败的步骤重试。

启用 compensate_on_failure() 后,工作流标记为失败之后会运行已完成步骤的补偿处理程序。随后,retry_workflow() 会抛出错误,因为工作流已经完成补偿。

支持的步骤类型

补偿处理程序可以添加到以下步骤:

  • 顺序 then() 步骤
  • parallel() 组
  • for_each() 步骤
  • run_workflow() 步骤
  • delay() 延迟步骤
  • wait_for_signal() 信号步骤
  • wait_for_workflow() 工作流依赖步骤

对于 run_workflow() 和 for_each(),补偿快照会在嵌套工作或分支工作全部完成后记录。

on_cancel() 与补偿的区别

使用 compensate_with() 按逆序撤销已完成步骤产生的副作用。

使用 on_cancel() 添加一个工作流级清理钩子,使其在工作流被显式取消时运行。