Go: Повторный requestid возвращает прежнюю бронь — задача с проверкой
Практическая задача на Go по теме «Повторный request_id возвращает прежнюю бронь». Условие содержит контракт функций, предоставленные типы и требования к результату. Используйте выданный шаблон и сохраняйте его публичные объявления. Перед проверкой разберите успешный путь, обработку ошибок и отмену операции, когда она предусмотрена контрактом. Здесь оценивается конкретный компонент сервиса; в полном курсе микросервисов на Go эти компоненты связываются с HTTP, PostgreSQL, gRPC и Kafka.
Повторный request_id возвращает прежнюю бронь
Реализуйте функцию IdempotentBook, которая обеспечивает идемпотентное бронирование места на показ.
Дополните TODO в редакторе и отправьте весь код, сохранив package main, импорты, предоставленные типы и публичную функцию RunScenario. Не добавляйте свою функцию main: JSON-адаптер запуска платформа добавит сама. Скрытые входы и ожидаемые результаты находятся на стороне проверки.
Входные данные уже проверены и нормализованы; числовые поля не требуют дополнительной проверки или преобразования. Задача посвящена решениям над предоставленным интерфейсом хранилища. SQL, подключение к базе данных, сеть и внешние модули не нужны.
Предоставленное хранилище само управляет транзакцией: успешный Book возвращает сохранённую бронь после завершённого commit, а ErrSeatUnavailable и ErrRequestIDConflict — только после завершённого успешного rollback. Каждый вызов ByRequestID — независимое чтение текущего состояния вне предыдущей попытки; найденная запись относится точно к переданному RequestID.
type Booking struct {
ID int64
ShowID int64
SeatNo int32
CustomerID int64
RequestID string
}
type BookingStore interface {
ByRequestID(context.Context, string) (Booking, error)
Book(context.Context, Booking) (Booking, error)
}
type Result struct {
Status string
Booking Booking
}
// Сентинели: ErrNotFound, ErrSeatUnavailable, ErrRequestIDConflict, ErrConflict
func IdempotentBook(ctx context.Context, repo BookingStore, in Booking) Result
Требуемое поведение:
Для сравнения запроса и сохранённой брони значимы только ShowID, SeatNo, CustomerID. Предложенный ID не влияет на равенство; RequestID служит точным ключом поиска.
| Наблюдаемый результат | Статус и данные |
|---|---|
| Первичный поиск нашёл бронь с равными значимыми полями | replayed, найденная бронь целиком; создание не требуется |
| Первичный поиск нашёл бронь с отличающимися значимыми полями | conflict; создание не требуется |
Первичный поиск завершился любой ошибкой, кроме ErrNotFound |
storage_error; создание не требуется |
Первичный поиск подтвердил отсутствие ключа (ErrNotFound), а единственная попытка Book успешна |
created, бронь целиком из результата Book; дополнительного поиска нет |
Book завершился ErrSeatUnavailable или ErrRequestIDConflict, а новое чтение нашло бронь с равными значимыми полями |
replayed, бронь целиком из нового чтения |
| После любой из этих двух ошибок новое чтение нашло бронь с отличающимися значимыми полями | conflict |
После ErrSeatUnavailable новое чтение подтвердило отсутствие ключа (ErrNotFound) |
seat_unavailable |
После ErrRequestIDConflict новое чтение подтвердило отсутствие ключа (ErrNotFound) |
conflict |
| После любой из этих двух ошибок новое чтение завершилось иной ошибкой | storage_error |
Book завершился ErrConflict |
conflict, без дополнительного поиска |
Book завершился любой иной ошибкой, включая ошибку commit |
storage_error, без дополнительного поиска |
Правила обращений и результата:
- Первичный
ByRequestIDобязателен ровно один раз. ЕдинственныйBookдопустим только при подтверждённом отсутствии ключа. Новое чтение обязательно ровно один раз только послеErrSeatUnavailableилиErrRequestIDConflictотBook. - Во все обращения передавайте исходный
ctx, даже если он уже отменён, и неизменённыйin.RequestID; вBookпередавайте исходныйinцеликом. Самостоятельная проверка отмены контекста не должна заменять обязательное обращение к хранилищу. - Ошибки распознавайте через
errors.Is, включая обёрнутые ошибки. Одинаковый текст без совпадения поerrors.Isне означает совпадение с сентинелем. - При ненулевой ошибке игнорируйте частично возвращённый
Booking. Bookingзаполняется только дляcreatedиreplayed, причём авторитетна вся запись, возвращённая хранилищем. Дляconflict,seat_unavailableиstorage_errorполеBookingимеет нулевое значение.- На любом пути допустимы не более одного
Bookи двухByRequestID. Циклы и повторные попытки создания не допускаются.
Подсказки
- Идемпотентный повтор относится к сохранённой брони: новый предложенный ID не меняет личность уже выполненного запроса.
- Отсутствие ключа при новом чтении означает, что прежняя бронь для этого запроса не найдена. Значение этого результата зависит от причины неудачной попытки создания.
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Go: Принять только полный ответ о последней статье — задача с проверкой
- HTTP-клиент поиска на Go: обработка ответа и ошибок — задача
- Go: Декодирование артефакта из JSON — задача с проверкой
- Go: Обязательная и необязательная зависимость при отказе — задача с проверкой
- Go: HTTP-обработчик поиска задания через JobStore — задача с проверкой
- Go: HTTP-обработчик расчёта калорийности состава — задача с проверкой
