工作流防护措施
代理式工作流灵活多变,但也更容易创建重复运行,或让规划器生成超出预期的任务。Queuety 在工作流层面提供轻量级防护措施,让你在保留灵活性的同时仍能掌控工作流。
有关工作进程准入和逐作业成本元数据的更全面资源模型,请参阅 资源管理。
为工作流定义添加版本
使用 version() 为工作流定义添加应用层版本标签:
Queuety::workflow( 'research_run' )
->version( 'research.v2' )
->then( PlanResearchStep::class )
->then( DraftResearchSummaryStep::class )
->dispatch();
版本会与工作流状态一同存储,通过 workflow_status() 公开、由 wp queuety workflow status 输出,并包含在工作流导出数据中。
Queuety 还会为每次工作流运行存储确定性的 definition_hash。该哈希由序列化后的工作流定义生成;部署后,如果你需要准确识别正在执行的工作流形态,它会很有用。
让调度具备幂等性
如果调用方可能重试同一个请求,请使用 idempotency_key():
Queuety::workflow( 'research_run' )
->idempotency_key( 'brief:42:research' )
->then( PlanResearchStep::class )
->dispatch( [ 'brief_id' => 42 ] );
如果使用过的键再次用于调度工作流,Queuety 会返回原工作流 ID,而不是创建重复运行。键在所有工作流名称之间全局唯一,因此不同工作流可能共用同一个键时,请将工作流名称加入键中。
以下场景尤其适用:
- API 可能被客户端或网关重试的端点
- 可能收到重复投递的 webhook 消费方
- 规划器步骤应针对每个外部实体只创建一次编排运行
幂等键存储在 queuety_workflow_dispatch_keys 表中。
设置工作流预算
使用工作流预算,在运行超出预定范围时使其失败:
Queuety::workflow( 'research_run' )
->max_transitions( 20 )
->max_for_each_items( 12 )
->max_state_bytes( 32768 )
->max_cost_units( 40 )
->max_started_workflows( 8 )
->then( PlanResearchStep::class )
->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
->dispatch();
max_transitions()
限制运行失败前可以完成的工作流步骤数。这有助于保护会动态分支或可能通过 _next_step 返回同一区域的工作流。
max_for_each_items()
限制单个 for_each() 步骤可展开的运行时发现项目数。这适用于规划器/执行器系统,因为代理可能发现远超预期的分支任务。
max_state_bytes()
限制公开工作流状态的编码大小。这有助于避免长时间运行的工作流膨胀成大型数据块,导致检查、导出或重试变慢。
max_cost_units()
限制已完成步骤消耗的总成本单位。成本单位取自 Queuety 入队作业时解析的步骤或作业元数据。常规用户工作默认为 1,延迟和等待等编排占位步骤使用 0,处理器可以通过 config() 或作业属性设置更高的正值。只有步骤定义的 cost_units 可以将值设为 0。
如果工作流可能返回同一区域,或者 For-Each 展开的任务成本很高、无法仅靠步骤数反映,这项限制就很有用。反复调用高成本模型的规划器可能仍未超出 max_transitions(),但实际成本却超过了预期范围。
max_started_workflows()
限制通过 start_workflows() 或 start_agents() 启动的顶层工作流数量。子工作流调度前会检查此限制,因此如果将要创建的工作流组已超出预算,父工作流会失败,而不会只创建其中一部分。
超出预算时,Queuety 会立即使工作流失败,而不会重试该步骤。有一种例外:如果 Queuety::signal() 完成等待时,产生的状态转换超出预算,则异常会抛给 signal() 的调用方,信号插入会回滚,工作流则继续等待。
监控防护措施
工作流状态会公开以下信息:
definition_versiondefinition_hashidempotency_keybudget
budget 负载包含配置的限制和当前用量,其中包括当前公开状态的字节大小。
示例:
$state = Queuety::workflow_status( $workflow_id );
$state->definition_version; // 'research.v2'
$state->definition_hash; // '4c7a...'
$state->idempotency_key; // 'brief:42:research'
$state->budget; // [ 'max_transitions' => 20, ... ]