
# Перемотка рабочего процесса во времени

Queuety может вернуть рабочий процесс к предыдущему шагу и продолжить выполнение с этой точки. Это полезно, если шаг выдал неверный результат, если нужно повторить его с другой конфигурацией или если требуется восстановить данные после повреждения, не перезапуская весь рабочий процесс.

Перемотка использует [Журнал событий рабочего процесса](https://queuety.inline0.dev/ru/docs/workflows/event-log). В журнале должны быть данные `state_after` для целевого шага.

## Перемотка рабочего процесса

### PHP API

Вызовите `Queuety::rewind_workflow()`, указав ID рабочего процесса и индекс шага, к которому нужно вернуться:

```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. В журнале событий запрашивается значение `state_after`, записанное после завершения шага N
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` |
