持久化延迟
工作流可以使用构建器方法 delay() 在步骤之间暂停一段固定时长。延迟步骤具有持久性:延迟会存储在数据库中,因此 worker 重启、部署或服务器重新启动后仍会保留。
->delay() 方法
在工作流链中的任意位置添加延迟步骤:
PHP
use Queuety\Queuety;
Queuety::workflow( 'drip_campaign' )
->then( SendWelcomeEmailHandler::class )
->delay( days: 1 )
->then( SendFollowUpEmailHandler::class )
->delay( days: 3 )
->then( SendFinalEmailHandler::class )
->dispatch( [ 'user_id' => 42 ] );
工作流将会:
- 运行
SendWelcomeEmailHandler - 等待 1 天
- 运行
SendFollowUpEmailHandler - 等待 3 天
- 运行
SendFinalEmailHandler
时长参数
delay() 方法接受任意组合的命名时长参数:
| 参数 | 类型 | 说明 |
|---|---|---|
$seconds |
int |
等待秒数 |
$minutes |
int |
等待分钟数 |
$hours |
int |
等待小时数 |
$days |
int |
等待天数 |
所有值会相加。以下写法等效:
PHP
->delay( seconds: 3600 )
->delay( minutes: 60 )
->delay( hours: 1 )
你可以将它们组合使用:
PHP
->delay( hours: 1, minutes: 30 ) // 90 minutes total
延迟步骤的工作方式
工作流到达延迟步骤时,Queuety 会分派一个内部 __queuety_delay 作业,并将其 available_at 列设为当前时间加上延迟时长。该作业会留在数据库中,直到延迟时间结束后,才会被 worker 领取。
这意味着:
- 无需轮询。 Worker 不会反复检查延迟。时间一到,作业就会自动变为可用。
- 不占用内存。 等待期间没有任何进程在运行。延迟仅作为数据库中的一行记录存在。
- 重启后仍然有效。 即使 worker 重启,延迟作业仍会留在队列中,并保留正确的
available_at时间戳。
延迟结束后,延迟作业一旦被领取,工作流就会自动进入下一步。
示例:延迟通知
用户注册 1 小时后发送提醒,但前提是用户尚未完成新手引导:
PHP
Queuety::workflow( 'onboarding_reminder' )
->then( CreateAccountHandler::class )
->delay( hours: 1 )
->then( CheckOnboardingHandler::class )
->then( SendReminderHandler::class )
->dispatch( [ 'email' => 'user@example.com' ] );
CheckOnboardingHandler 步骤可以检查状态,并使用 条件分支,在新手引导已完成时跳过提醒。
示例:带退避的重试
在类似重试的步骤之间插入有意设置的延迟:
PHP
Queuety::workflow( 'poll_external_api' )
->then( CheckStatusHandler::class, 'check' )
->delay( minutes: 5 )
->then( CheckStatusHandler::class, 'recheck' )
->delay( minutes: 15 )
->then( CheckStatusHandler::class, 'final_check' )
->then( ProcessResultHandler::class )
->dispatch( [ 'external_id' => 'abc-123' ] );
多个延迟
一个工作流可以包含任意数量的延迟步骤。每个延迟都相互独立,并在工作流状态中通过顺序名称(delay_0、delay_1 等)进行跟踪。
PHP
Queuety::workflow( 'multi_step_drip' )
->then( StepA::class )
->delay( hours: 2 )
->then( StepB::class )
->delay( days: 1 )
->then( StepC::class )
->delay( minutes: 30 )
->then( StepD::class )
->dispatch( $payload );