Повторіть виклик, не роблячи роботу двічі

PHP

Дайте запуску чи руху кредитів ключ, який називає його одиницю роботи, — тоді на повтор, від SDK, від вашої черги чи від вашого коду, відповідять, а не зроблять роботу знову.

5 хв читання

Запуск флоу й рух кредитів несуть ключ ідемпотентності. Ключ називає одну одиницю роботи. Коли той самий виклик приходить ще раз під тим самим ключем, Slen відповідає на нього, а не робить роботу знову, — тому виклик, повторений після тайм-ауту, падіння чи повтору вашої черги, — це не друге виконання, не друга витрата й не друге поповнення.

Ключ, який створює SDK, і ключ, який передаєте ви

Ключ приймають п’ять викликів: operations.execute(), operations.executeAsync(), customers.topUp(), customers.charge() і customers.adjust(). Ключ — це idempotencyKey опцій виклику: ExecuteOptions запуску, MovementOptions руху кредитів — ті самі імена в обох SDK. Коли ви не передаєте ключ, SDK створює для цього виклику новий випадковий.

  • Ключ, створений SDK, покриває лише власні повтори SDK. SDK надсилає запит ще раз під тим самим ключем, коли відповіді не було, після 429 або 503 — Повтори й тайм-аути.

  • Виклик, який ваш код робить ще раз, — повтор вашої черги, друге натискання кнопки — отримує новий випадковий ключ, а новий ключ — це нова робота: флоу виконується знову, кредити рухаються знову.

  • Порожній ключ, який ви передали, відхиляється до надсилання запиту, з кодом invalid_request. SDK ніколи не підставляє на його місце свій.

Попередження:

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

Вибрати ключ

Робіть ключ з одиниці роботи, щоб кожен повтор роботи ніс той самий ключ, а наступна одиниця роботи отримувала новий: замовлення та його крок (order-42:email), рахунок-фактура та його поповнення (invoice-7781:topup) або задача вашої черги, яка надсилає виклик.

PHP
use Slen\Sdk\IdempotencyKeys;

// The id of the job of your own queue that sends this request.
$jobId = 'a1f7c2e9';
$key = IdempotencyKeys::forJob($jobId, 'generate_email');

IdempotencyKeys::forJob() робить job:<id>:<operation> — один ключ на всі спроби задачі. Задача, яка виконується знову, отримує назад перше виконання. IdempotencyKeys::generate() робить випадковий ключ — той, який SDK створює, коли ви не передали свій.

  • Ключ — не довший за 190 символів. Довший відхиляється з 422, перш ніж щось виконається.

  • Ключ належить проєкту API-ключа. Усередині проєкту давайте кожній одиниці роботи свій ключ.

Чим відповідають на повтор

PHP
use Slen\Sdk\Modules\Operations\Options\ExecuteOptions;

$input = ['messages' => [['role' => 'user', 'content' => 'Write a short follow-up email.']]];

$execution = $slen->operations()->execute('generate_email', $input, new ExecuteOptions(idempotencyKey: $key));

echo $execution->status->value, PHP_EOL;
PHP
// The queue runs the same job again, so the key is the same.
$again = $slen->operations()->execute('generate_email', $input, new ExecuteOptions(idempotencyKey: $key));

if ($again->replayed) {
    echo "Execution {$again->executionId} ran once. This answer is a replay.", PHP_EOL;
}
ВикликПовтор під його ключем
ЗапускВиконання, яке почав перший запит, у тому стані, у якому воно є в цю мить, із replayed, що дорівнює true. Флоу не виконується знову
Поповнення, списання чи коригуванняПерша відповідь, протягом 24 годин. Після цього — рахунок таким, яким він став. Кредити рухаються один раз. Відхилений рух не зберігається, і його повтор — нова спроба
  • На виконання, яке не закінчилося, відповідають 202 і статусом queued, waiting або running — running, коли виконання першого запиту ще триває.

  • На виконання, яке закінчилося, відповідають 200 і його результатом. Так і тоді, коли перший запит закінчився помилкою: повтор читає статус виконання та його error_code.

  • На повторі може прийти cost.actual, коли в першій відповіді його не було: розрахунок за виклики моделей іде після кінця виконання.

Інші виклики SDK ключа не приймають. Читання нічого не змінює, а створення клієнта, налаштування рахунку, блокування й розблокування лишають той самий стан, скільки б разів їх не надіслали. Видалення, яке SDK повторив, коли відповіді не було, вважається зробленим, коли клієнта вже немає, — Повтори й тайм-аути. Ті самі відповіді в термінах API наводить стаття Ідемпотентність.

Той самий ключ з іншим запитом

PHP
use Slen\Sdk\Exceptions\IdempotencyConflictException;

try {
    $slen->operations()->execute(
        'generate_email',
        ['messages' => [['role' => 'user', 'content' => 'Write a short thank-you email.']]],
        new ExecuteOptions(idempotencyKey: $key),
    );
} catch (IdempotencyConflictException $exception) {
    echo "Refused: {$exception->errorCode}", PHP_EOL;
}

Ключ, який уже називає одну одиницю роботи, не приймає іншу: API відповідає 409 із кодом idempotency_conflict, нічого не виконується й нічого не рухається, а SDK кидає помилку.

Виняток — IdempotencyConflictException. idempotency_in_progress приходить тим самим винятком: перший запит під цим ключем ще не закінчився. Надішліть виклик ще раз пізніше, під тим самим ключем.

  • Для запуску інший вхід, інший контекст, інший клієнт чи інший режим — це інший запит.

  • Для руху кредитів інший клієнт, тип кредитів, вид чи сума — це інший запит, а в перші 24 години — й інша примітка.

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

Що читати далі