
# 工作流时间回溯

Queuety 可以将工作流回退到之前的步骤，并从该步骤恢复执行。当某个步骤产生了错误输出、你希望使用不同配置重试，或需要从损坏的数据中恢复而不重启整个工作流时，这种方式很有用。

回退依赖 [工作流事件日志](https://queuety.inline0.dev/zh/docs/workflows/event-log)。事件日志必须包含目标步骤的 `state_after` 数据。

## 回退工作流

### PHP API

使用工作流 ID 和要回退到的步骤索引调用 `Queuety::rewind_workflow()`：

```php
use Queuety\Queuety;

// Rewind workflow 42 to step 1.
// The state is restored to the snapshot taken after step 1 completed,
// and step 2 is enqueued for re-execution.
Queuety::rewind_workflow( $workflow_id, to_step: 1 );
```

`to_step` 参数是要恢复其已完成状态的步骤从零开始的索引。执行会从下一步骤（to_step + 1）恢复。

### CLI

```bash
wp queuety workflow rewind <id> <step>
```

| 选项 | 说明 |
|---|---|
| `<id>` | 工作流 ID（必填） |
| `<step>` | 要回退到的步骤索引，从 0 开始（必填） |

```bash
wp queuety workflow rewind 42 1
```

## 工作原理

将工作流回退到步骤 N 时：

1. 查询事件日志，获取步骤 N 完成后记录的 `state_after` 值
2. 如果不存在快照，则抛出 `RuntimeException`
3. 锁定工作流行
4. 将工作流状态替换为快照，同时保留当前工作流行中的所有保留键（`_steps`、`_queue`、`_priority` 等）
5. 将 `current_step` 设为 N + 1，并将 `status` 设为 `running`
6. 清除所有 `error_message` 和 `failed_at` 字段
7. 将索引为 N + 1 的步骤加入队列以供处理
8. 记录一条 `workflow_rewound` 日志事件

随后，工作进程会取出已加入队列的步骤，工作流从该处起照常继续运行。

## 要求

回退需要事件日志中有 `state_after` 数据。每次 `step_completed` 事件都会自动记录该数据。如果事件日志已被清理（通过 `WorkflowEventLog::prune()`），且目标步骤的状态不再存在，回退就会失败。

请确保事件日志的保留期限涵盖你可能需要回退到的时间段。

## 使用场景

### 修复有缺陷的步骤处理程序

如果某个步骤处理程序存在缺陷并产生了错误输出，你可以部署修复，然后回退：

```php
// Step 2 (CallLLMHandler) produced garbled output due to a prompt bug.
// After fixing CallLLMHandler, rewind to step 1 so step 2 runs again
// with the corrected handler.
Queuety::rewind_workflow( $workflow_id, to_step: 1 );
```

### 使用不同配置重试

当步骤因外部因素（API 速率限制、凭据错误）而失败时，修正配置并回退以重新运行：

```php
// Step 3 failed because the API key was expired.
// After updating the key, rewind to step 2 so step 3 retries.
Queuety::rewind_workflow( $workflow_id, to_step: 2 );
```

### 从错误数据中恢复

如果较早的步骤向状态中写入了错误数据，请回退到已知正常的快照：

```php
// Step 0 fetched correct data, but step 1 corrupted it.
// Rewind to step 0 to restore the good state and re-run step 1.
Queuety::rewind_workflow( $workflow_id, to_step: 0 );
```

## 与重试的比较

| 方面 | `retry_workflow()` | `rewind_workflow()` |
|---|---|---|
| 恢复位置 | 失败的步骤 | 任意先前步骤 |
| 状态 | 当前工作流状态 | 从事件日志 `state_after` 恢复 |
| 要求 | 工作流处于 `failed` 状态 | 目标步骤存在事件日志快照 |
| 操作后状态 | `running` | `running` |
| 日志事件 | 无 | `workflow_rewound` |
