跳转到正文

工作流取消

可以通过编程方式或经由 CLI 取消工作流。工作流取消后,Queuety 会将其状态设为 cancelled,将所有待处理或正在处理的任务移入封存,并运行可选的清理处理程序。

注册清理处理程序

在工作流构建器上使用 on_cancel() 注册一个在工作流取消时运行的类。处理程序类必须实现 handle( array $state ): void 方法。

PHP
use Queuety\Queuety;

Queuety::workflow( 'import_data' )
    ->then( FetchDataHandler::class )
    ->then( TransformDataHandler::class )
    ->then( LoadDataHandler::class )
    ->on_cancel( ImportCleanupHandler::class )
    ->dispatch( [ 'source_url' => $url ] );

清理处理程序会接收公开的工作流状态(所有名称不以 _ 开头的键):

PHP
class ImportCleanupHandler {

    public function handle( array $state ): void {
        // Clean up any partial imports.
        if ( isset( $state['temp_table'] ) ) {
            global $wpdb;
            $wpdb->query( "DROP TABLE IF EXISTS {$state['temp_table']}" );
        }

        // Notify the user.
        wp_mail(
            $state['notify_email'] ?? '',
            'Import cancelled',
            'Your data import was cancelled.'
        );
    }
}

通过 PHP 取消

使用工作流 ID 调用 Queuety::cancel_workflow():

PHP
Queuety::cancel_workflow( $workflow_id );

此方法会:

  1. 锁定工作流行
  2. 将工作流状态设为 cancelled
  3. 将该工作流的所有待处理和正在处理的任务移入封存,并附上消息 "Workflow cancelled"
  4. 记录 workflow_cancelled 事件并提交
  5. 按相反顺序运行已完成步骤的补偿处理程序(如果通过 compensate_with() 注册过)
  6. 运行 on_cancel 清理处理程序(如果已注册)

如果工作流已处于 completed 或 cancelled 状态,就会抛出 RuntimeException。

通过 CLI 取消

命令行
wp queuety workflow cancel <id>
选项 说明
<id> 要取消的工作流 ID(必填)
命令行
wp queuety workflow cancel 42

取消时会发生什么

工作流取消时:

  • 状态 更改为 cancelled
  • 步骤补偿处理程序 按完成顺序的逆序运行(如果你通过 compensate_with() 添加了它们)
  • 清理处理程序 在工作流行标记为 cancelled 后运行
  • 该工作流的 待处理任务 会立即移入封存
  • 该工作流的 正在处理的任务 会移入封存;正在执行的处理程序完成后,其输出会被丢弃,工作流也不会继续推进
  • 先前步骤的 已完成任务 保持原样
  • 记录包含事件 workflow_cancelled 的 日志条目

已取消与失败

方面 失败 已取消
触发条件 某个步骤耗尽重试次数 显式调用 cancel_workflow()
状态 failed cancelled
能否重试 可以,通过 retry_workflow() 重试,除非工作流已经完成补偿 不可以
清理处理程序 不会调用 如果通过 on_cancel() 注册,则会调用
日志事件 workflow_failed workflow_cancelled

示例:取消前进行确认

一种常见模式是在取消前检查工作流状态:

PHP
$status = Queuety::workflow_status( $workflow_id );

if ( null === $status ) {
    throw new \RuntimeException( 'Workflow not found.' );
}

if ( 'running' === $status->status->value || 'paused' === $status->status->value ) {
    Queuety::cancel_workflow( $workflow_id );
}