Перейти до основного вмісту
Версія: 2.0

Cancel і Terminate

Цей посібник описує вбудований Laravel API Workflow\V2\WorkflowStub. Для клієнтів і worker у сервісному режимі використовуйте посібник PHP SDK, довідник скасування Python або API життєвого циклу Rust.

Cancel і terminate — це повноцінні стійкі команди, які закривають активний workflow. Обидві записуються в історію команд, створюють типізовані події історії та відображаються у Waterline.

У поточному вбудованому API обидві команди закривають запуск негайно. Cancel записує результат cancelled, а terminate — terminated. Жодна не планує очищення всередині закритого workflow. Вбудований Laravel також надає requestCancellation() для кооперативного очищення з обмеженим часом. Server і SDK для PHP, Python та Rust підтримують окремий кооперативний запит із worker, які явно його вмикають. Контракт можливостей, кінцевих термінів, очищення й відновлення наведено в розділі Кооперативне скасування.

Cancel​

Cancel негайно переводить запуск у стан cancelled і записує стійку історію.

use Workflow\V2\WorkflowStub;

$workflow = WorkflowStub::load('order-123');

$result = $workflow->cancel();

$result->accepted(); // true
$result->outcome(); // "cancelled"
$result->commandId(); // Durable command id
$result->reason(); // null (no reason provided)

Cancel із причиною​

Можна надати структуровану причину, щоб розрізняти скасування користувачем, політикою та оператором у журналі аудиту, історії команд і Waterline.

$result = $workflow->cancel('Customer requested cancellation');

$result->reason(); // "Customer requested cancellation"

Причина зберігається в стійкому записі команди та типізованих подіях історії CancelRequested і WorkflowCancelled, тому залишається доступною під час replay, експорту та автономного аналізу.

Дія cancel​

Коли команду cancel прийнято, рушій закриває всі відкриті виконання activity й очікувані timer, переводить запуск у стан cancelled та відновлює батьківський workflow, який очікує на скасований дочірній, щоб той міг отримати результат.

Коли cancel відхиляється​

  • Екземпляр ще не розпочався: rejection_reason = instance_not_started
  • Поточний запуск уже закрито: rejection_reason = run_not_active
  • Cancel для вибраного запуску адресує історичний, а не поточний запуск: rejection_reason = selected_run_not_current

Terminate​

Terminate негайно закриває активний workflow без планування подальшого коду workflow. Як і cancel, він не надає часового вікна очищення. Використовуйте його, коли потрібен окремий результат terminated.

$result = $workflow->terminate();

$result->accepted(); // true
$result->outcome(); // "terminated"

Terminate із причиною​

$result = $workflow->terminate('Operator emergency shutdown');

$result->reason(); // "Operator emergency shutdown"

Дія terminate​

Terminate виконує ті самі транзакційні кроки, що й cancel, але:

  • Натомість записує події історії TerminateRequested та WorkflowTerminated.
  • Створює запис WorkflowFailure із failure_category = terminated та propagation_kind = terminated.
  • Задає closed_reason = terminated для запуску.
  • Не планує подальше виконання коду workflow.

Коли terminate відхиляється​

Діють ті самі умови відхилення, що й для cancel.

Команди для вибраного запуску​

Cancel і terminate можуть адресувати конкретний запуск замість поточного запуску екземпляра.

$selectedRun = WorkflowStub::loadRun($runId);
$result = $selectedRun->attemptCancel('Draining old run');

$result->targetScope(); // "run"

Команди для вибраного запуску відхиляються з selected_run_not_current, якщо адресований запуск уже не є поточним запуском екземпляра. Відповідь містить requested_run_id (адресований запуск) та resolved_run_id (поточний запуск, який слід використовувати далі).

API без винятків​

Використовуйте attemptCancel() та attemptTerminate() для обробки відхилення без винятків:

$result = $workflow->attemptCancel('Duplicate order');

if ($result->rejected()) {
$result->rejectionReason(); // e.g. "run_not_active"
}

cancel() та terminate() спричиняють LogicException у разі відхилення.

Webhook​

Cancel і terminate доступні через маршрути webhook:

POST /webhooks/instances/{workflowId}/cancel
POST /webhooks/instances/{workflowId}/terminate
POST /webhooks/instances/{workflowId}/runs/{runId}/cancel
POST /webhooks/instances/{workflowId}/runs/{runId}/terminate

Передайте причину в тілі запиту:

{
"reason": "Operator: duplicate order"
}

Відповідь містить результат команди, публічний ID екземпляра та причину:

{
"outcome": "cancelled",
"workflow_id": "order-123",
"run_id": "01J10000000000000000000021",
"reason": "Operator: duplicate order",
"command_id": "01J40000000000000000000021",
"command_status": "accepted"
}

Скасування не є помилкою для випадкового перехоплення​

Скасування — це явний результат життєвого циклу, а не неочікувана помилка застосунку. У вбудованому пакеті Workflow\V2\Exceptions\WorkflowCancelledException успадковує \Error, а не \Exception. Блок catch (\Exception $e) його не перехопить, а catch (\Throwable $t) — перехопить.

Під час читання результату скасованого workflow перехоплюйте виняток за назвою, якщо потрібно відрізнити скасування від інших помилок. Перехоплення винятку результату не відкриває скасований запуск знову й не планує очищення всередині нього.

Waterline​

Waterline надає cancel і terminate як дії оператора в детальному перегляді вибраного запуску. Дані деталей містять прапорці can_cancel та can_terminate, визначені стійким станом.

Перегляд історії команд показує кожну команду cancel або terminate з причиною, ідентичністю ініціатора та результатом. Поле commands[*].reason містить причину, надану оператором або кодом виклику, якщо її було задано.

Відповідність станів​

Запуски cancelled та terminated потрапляють до категорії стану failed для маршрутизації списків. Поля status та closed_reason розрізняють їх:

СтанКатегорія стануПричина закриття
cancelledfailedcancelled
terminatedfailedterminated

Типізована історія​

Скасований запуск створює таку послідовність історії:

StartAccepted
WorkflowStarted
... (workflow progress) ...
CancelRequested <- reason field present when supplied
TimerCancelled <- for each open timer
ActivityCancelled <- for each open activity
WorkflowCancelled <- failure_id, failure_category, reason when supplied

Примусово завершений запуск створює:

StartAccepted
WorkflowStarted
... (workflow progress) ...
TerminateRequested <- reason field present when supplied
TimerCancelled <- for each open timer
ActivityCancelled <- for each open activity
WorkflowTerminated <- failure_id, failure_category, reason when supplied

Порівняння cancel і terminate​

CancelTerminate
Планується подальший код workflowНіНі
Відкриті activity скасовуютьсяТакТак
Відкриті timer скасовуютьсяТакТак
Метадані причиниТакТак
Стійка історія командТакТак
Батьківський workflow отримує дочірній результатТакТак
Записується помилкаТак (cancelled)Так (terminated)
Категорія стануfailedfailed
Причина закриттяcancelledterminated