
# 持久化延迟

工作流可以使用构建器方法 `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 ] );
```

工作流将会：

1. 运行 `SendWelcomeEmailHandler`
2. 等待 1 天
3. 运行 `SendFollowUpEmailHandler`
4. 等待 3 天
5. 运行 `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` 步骤可以检查状态，并使用 [条件分支](https://queuety.inline0.dev/zh/docs/workflows/conditional)，在新手引导已完成时跳过提醒。

## 示例：带退避的重试

在类似重试的步骤之间插入有意设置的延迟：

```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 );
```
