Повторите вызов, не делая работу дважды
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) или задача вашей очереди, которая отправляет вызов.
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-ключа. Внутри проекта давайте каждой единице работы свой ключ.
Чем отвечают на повтор
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;// 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 приводит статья Идемпотентность.
Тот же ключ с другим запросом
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 часа — и другое примечание.
Выполнение, которое упало, сохраняет свой ключ. Чтобы выполнить работу снова, после того как вы исправили запрос, отправьте его под новым ключом.
Что читать дальше
Идемпотентность — заголовок, какие запросы API его требуют и чем каждый отвечает на повтор.
Асинхронные запуски и ожидание — прочитайте результат выполнения, которое повтор застал незаконченным.
Клиенты и кредиты — движения кредитов и их ключи.