OpenAI-compatible API: idempotency key для повтора запроса
Запрос «OpenAI compatible API idempotency key повторный запрос» обычно появляется после timeout: клиент не знает, дошёл ли вызов, а повтор способен создать вторую задачу, письмо или запись. Идемпотентность — это не магический header и не обещание внешнего endpoint. Для прикладного процесса она начинается с локальной операции, уникального ключа, сохранённого состояния и понятной ветки для неизвестного результата. RussiaAPI — независимый сторонний API gateway; статья не предполагает, что любой маршрут принимает конкретный заголовок или гарантирует выполнение ровно один раз.
Отделите повтор транспорта от повторения действия
Потерянный HTTP-ответ не доказывает, что действие не началось. Сеть могла оборваться после принятия запроса, очередь могла продолжить работу, а локальный таймер мог истечь раньше внешнего процесса. Поэтому кнопка Retry не должна сразу создавать новую операцию. Сначала приложение ищет уже существующую запись по своему operation ID и показывает проверяемое состояние: ещё не начато, выполняется, завершено, отклонено или требует ручной проверки.
Полезно определить, какие операции вообще допустимо повторять. Чистое чтение или генерация черновика без дальнейшего эффекта обычно проще, чем отправка письма, изменение CRM или создание оплачиваемой задачи. Даже когда текстовый запрос кажется безопасным, его результат может быть связан с очередью, квотой или хранением. Не называйте любое повторение идемпотентным без доказательства в собственной модели данных и без теста негативных случаев.
Создайте ключ внутри вашего серверного процесса
Клиент может передать намерение, но сервер должен выдать или проверить application-owned operation ID, привязанный к аутентифицированному пользователю, tenant, типу операции и нормализованному набору параметров. Этот ID не должен содержать email, prompt, API-ключ или доступный из браузера секрет. Для одного логического действия храните один ключ; повтор той же формы обращения не создаёт новый ключ молча.
Не предполагается, что внешняя сторона принимает именно ваш ключ или конкретное имя заголовка. Если текущая документация маршрута описывает механизм идемпотентности, сверяйте имя, область действия и срок жизни с ней в день интеграции. Если такого механизма нет или он не подтверждён, локальная запись и проверка состояния остаются обязательными. Они уменьшают риск двойного решения внутри вашего приложения, но не дают обещания о поведении всех поставщиков.
Защитите первый запуск от гонки
Два одновременных запроса с одинаковым ключом часто возникают из-за двойного клика, мобильной сети или повторной доставки очереди. Проверки в памяти недостаточно: два процесса могут пройти её одновременно. Используйте транзакцию или уникальное ограничение на сочетание tenant, типа операции и ключа. Один процесс становится владельцем выполнения, а остальные получают сохранённый результат или статус ожидания, не выполняя работу второй раз.
У ключа должна быть привязка к неизменяемому отпечатку безопасных параметров. Если тот же ключ пришёл с другим tenant, другим получателем или другой суммой, это не «повтор» и не повод подставить данные. Остановите запрос и зафиксируйте безопасную ошибку сопоставления. Так один старый ключ не сможет стать инструментом для изменения другой операции, а оператор увидит локальную причину без раскрытия исходного payload.
Обрабатывайте timeout как неизвестный, а не как отказ
После timeout сначала запросите состояние локальной операции. Если оно уже завершено, покажите сохранённый исход. Если работа ещё идёт, верните пользователю понятный статус и способ проверить позже. Если состояние невозможно подтвердить, не рисуйте успешный результат и не отправляйте новый вызов автоматически: направьте операцию в ручную или отложенную сверку. Честная неопределённость лучше второго side effect.
Не связывайте retry с обещанием отсутствия списания, задержки или результата модели. Такие выводы требуют отдельной проверяемой информации о конкретном продукте и договоре. Логи должны содержать только operation ID, версию адаптера, время перехода и категорию исхода. Не записывайте заголовок Authorization, ключи, полный prompt или ответ провайдера. Для диагностики достаточно воспроизводимого синтетического сценария.
Тестируйте не только счастливый путь
В тестовом наборе нужны повтор до первого ответа, два параллельных повтора, новый payload со старым ключом, перезапуск процесса, сетевой обрыв после старта и поздний результат. Проверяйте, что код создаёт ровно одну локальную запись, не отправляет необратимое действие дважды и сообщает состояние без обмана. Заглушка внешнего вызова позволяет проверить эту логику без сети и без реального ключа.
После изменения очереди, базы, SDK, схемы или маршрута снова прогоните набор на staging. Сохраните дату теста, версию приложения и правила retention для локального состояния. Когда срок хранения ключа истёк, приложение не должно молча считать старый запрос новым; выберите явную политику: запрет, ручная сверка или безопасное создание нового намерения после подтверждения пользователя.
Пример безопасной server-side проверки
Пример ниже иллюстрирует только логику приложения. Он не делает сетевой вызов, не содержит реальных ключей и не доказывает поддержку конкретного endpoint. Проверьте актуальный договор и API-контракт перед подключением рабочего маршрута.
const operations = new Map();
export function beginOperation({ tenantId, key, fingerprint }) {
const id = tenantId + ':' + key;
const previous = operations.get(id);
if (previous && previous.fingerprint !== fingerprint) return { status: 'key_mismatch' };
if (previous) return { status: previous.status, operationId: id };
operations.set(id, { fingerprint, status: 'pending' });
return { status: 'created', operationId: id };
}
// Use a database uniqueness constraint in production; this example sends no network request.Граница ответственности и данных
Это инженерный шаблон для клиентского приложения, а не гарантия возможностей внешнего API. Не помещайте в браузер, тикет, статью или обычный журнал API-ключи, заголовок Authorization, cookie, ключи поставщиков, полный prompt или персональные данные. Условия обработки данных, права на контент и применимые требования проверяются по политике организации, договору и с ответственным специалистом.
Контроль перед выпуском
Перед release проверьте синтетический сценарий, запреты на секреты и персональные данные в логах, роли и tenant boundary, понятное сообщение для пользователя и ручную ветку для неизвестного результата. Сохраните дату, версию адаптера и результат теста. При обновлении SDK, модели, schema или маршрута повторите проверку; не переносите выводы старого теста на новый контракт.
Для выбора маршрута откройте RussiaAPI и сверяйте действующие условия в каталоге. Используйте только ключ своего аккаунта на сервере. RussiaAPI не является официальным представителем упомянутых поставщиков; доступность моделей, функций, цены, лимиты и правила обработки данных требуют отдельного подтверждения.
Полезные материалы
IETF: Idempotency-Key Header Field · AWS Builders Library: Making retries safe with idempotent APIs
FAQ
Можно ли просто повторить запрос после timeout?
Нет. Timeout означает неизвестный исход, а не гарантированный отказ. Сначала найдите локальную операцию по ключу, проверьте состояние и только затем выберите безопасную ветку: ожидание, сохранённый результат или ручную сверку.
Должен ли idempotency key понимать каждый endpoint?
Нет. Механизм внешнего endpoint зависит от текущего контракта. Даже если он документирован, приложению нужны собственные запись операции, уникальность, привязка к tenant и проверка результата. Не предполагаете имя header или гарантию для всех маршрутов.
Можно ли использовать один ключ для изменённых параметров?
Нет. Один ключ относится к одному логическому намерению. Если параметры, tenant или получатель изменились, верните понятную ошибку сопоставления и создайте новое намерение только после нужного подтверждения.
Следующий шаг
Продолжите с материалами: Контрактные тесты OpenAI-compatible API · Надёжность batch-задач · Idempotency и статус batch-задачи. Затем проверьте текущие условия и безопасно протестируйте интеграцию на staging перед production-трафиком.