Go: Один requestid для вызова и выяснения результата — задача с проверкой
Практическая задача на Go по теме «Один request_id для вызова и выяснения результата». Условие содержит контракт функций, предоставленные типы и требования к результату. Используйте выданный шаблон и сохраняйте его публичные объявления. Перед проверкой разберите успешный путь, обработку ошибок и отмену операции, когда она предусмотрена контрактом. Здесь оценивается конкретный компонент сервиса; в полном курсе микросервисов на Go эти компоненты связываются с HTTP, PostgreSQL, gRPC и Kafka.
Вы разрабатываете клиент для сервиса создания почтовых этикеток. Прежде чем открыть сетевое соединение, вызывающий код создаёт идентификатор намерения и сохраняет его вместе с идентификатором посылки. Если транспорт прервётся после отправки POST — клиент не узнает из одной лишь ошибки, дошёл ли запрос до сервиса. Именно поэтому тот же идентификатор намерения используется для последующего GET: оба вызова относятся к одному намерению.
Реализуйте две функции сборки запросов. Они получают уже сохранённую операцию и контекст; они не выполняют запросы, не генерируют идентификаторы и не хранят состояние.
Предоставленный тип:
type LabelOperation struct {
RequestID string // идентификатор намерения, создан и сохранён caller-ом до первого POST
ParcelID string // посылка, для которой создаётся этикетка
}
Функции для реализации:
func BuildLabelCreate(ctx context.Context, baseURL string, op LabelOperation) (*http.Request, error)
func BuildLabelLookup(ctx context.Context, baseURL string, op LabelOperation) (*http.Request, error)
Дополните TODO в редакторе и отправьте весь код, сохранив package main, импорты, предоставленные типы и публичную функцию RunScenario. Не добавляйте свою функцию main: JSON-адаптер запуска платформа добавит сама. Скрытые входы и ожидаемые результаты находятся на стороне проверки.
BuildLabelCreate собирает POST-запрос:
- Метод:
POST - URL:
baseURL + "/labels" - Заголовок:
Content-Type: application/json - Тело: один JSON-объект ровно с двумя строковыми полями —
request_idравноop.RequestIDиparcel_idравноop.ParcelID. Дополнительных полей нет. Порядок полей и пробелы не оцениваются.
BuildLabelLookup собирает GET-запрос:
- Метод:
GET - URL:
baseURL + "/label-requests/" + op.RequestID - Тело отсутствует.
Оба запроса должны содержать переданный ctx без замены. Вызывающий код может передать разные контексты для POST и для GET. Уже отменённый контекст остаётся отменённым в запросе — подменять его на context.Background() нельзя.
Почему один и тот же RequestID для POST и GET:
После timeout меняющего POST клиент не может по одной ошибке определить, был ли запрос принят сервисом. Lookup с тем же op.RequestID читает снимок состояния того же намерения. Если сервис вернул 200 state=created — операция была завершена (ответ на POST просто не дошёл). Если 200 state=processing — принята, ещё выполняется. Если 404 — записи нет на момент чтения, но это не доказывает, что POST никогда не был принят: он мог ещё быть в пути. Функции сборки запросов обеспечивают корреляцию по идентификатору; серверная устойчивость — отдельная тема.
Гарантированный вход (проверка не требуется):
ctxне равен nilbaseURL— корректный HTTP origin без пути, завершающего/, query, fragment и userinfoop.RequestIDиop.ParcelIDнепустые, состоят только из символов[A-Za-z0-9_-]
Для гарантированно корректного входа каждая функция должна вернуть ненулевой *http.Request и nil в качестве ошибки. Это требование действует и при уже отменённом переданном контексте: запрос должен быть создан с этим контекстом.
Ограничения реализации:
Функции только собирают запросы. Не выполняйте HTTP-вызов, retry или автоматический lookup. Не генерируйте новые идентификаторы. Не меняйте op. Не используйте изменяемое глобальное состояние. Не декодируйте ответы. Не подменяйте предоставленный контекст. Не печатайте ничего в stdout.
Доступные пакеты: bytes, context, encoding/json, fmt, io, net/http, net/http/httptest.
Вопрос: Клиент сохранил операцию с RequestID = "req-55", отправил POST /labels и получил транспортную ошибку без HTTP-ответа. Затем клиент выполнил GET /label-requests/req-55 и получил 404. Можно ли из одного этого 404 сделать вывод, что POST никогда не был принят сервисом, и немедленно отправить второй POST с новым идентификатором? Обоснуйте.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Go: Принять только полный ответ о последней статье — задача с проверкой
- HTTP-клиент поиска на Go: обработка ответа и ошибок — задача
- Go: Декодирование артефакта из JSON — задача с проверкой
- Go: Обязательная и необязательная зависимость при отказе — задача с проверкой
- Go: HTTP-обработчик поиска задания через JobStore — задача с проверкой
- Go: HTTP-обработчик расчёта калорийности состава — задача с проверкой
