Генерация изображения может завершиться позже, чем браузерный HTTP-запрос. Поэтому интерфейс должен отслеживать задачу по ID, а не считать нажатие кнопки или открытый preview признаком готового файла.
Минимальный job workflow
Клиент отправляет текст и параметры серверу. Сервер проверяет пользователя, размер ввода и допустимые параметры, затем создаёт job со статусом queued и возвращает его ID. Фоновый worker переводит запись в running, вызывает выбранный API модели, сохраняет результат и завершает задачу как succeeded либо failed. Клиент опрашивает собственный endpoint статуса и показывает именно сохранённое состояние.
Это схема приложения, не утверждение, что конкретный Images API предоставляет очередь или статусы: её создаёт владелец приложения. Руководство OpenAI по Images and vision описывает API для работы с изображениями; состав job scheduler, хранение результата и права доступа в него не входят.
Повторы и восстановление
Если пользователь повторил HTTP-запрос после потери связи, сервер должен понять, относится ли он к той же задаче. Сохраняй client request ID/idempotency key, пользователя и состояние; повтор с тем же ключом возвращает существующий job, а не запускает новую платную генерацию. Для вызова провайдера зафиксируй число попыток и классификацию ошибок: временная сеть может допускать ограниченный retry, неверные параметры — нет. После установленного предела помечай задачу failed и показывай понятное действие вместо бесконечного spinner.
Если процесс прервался после сохранения изображения, но до обновления строки job, recovery-процесс должен сверить job ID и объект в хранилище, а не генерировать файл заново автоматически. Определи, когда очищать временные файлы и как отменять уже начатую задачу. Отмена браузерного fetch сама по себе не гарантирует отмену работы у провайдера.
Доступ к файлу
Запрашивай результат по своему asset ID и сначала проверяй владельца записи. Не принимай произвольный URL для скачивания файла сервером: это открывает риск SSRF. OWASP SSRF Prevention Cheat Sheet рекомендует ограничивать назначения серверных запросов и проверять разрешённые адреса; безопаснее скачивать только из известного origin поставщика. Проверяй размер и фактический формат содержимого, храни файл закрытым по умолчанию и выдавай ограниченную по времени ссылку только после проверки доступа.
Пройди один обычный сценарий и три отказа: повторный submit, таймаут провайдера и открытие asset ID другим пользователем. Убедись, что лимит retry не создаёт скрытые повторные расходы, а чужой пользователь получает отказ даже при знании ID. Результаты здесь — проектные критерии, код не запускался.
