> Как гарантировать, что заказ не будет выполнен без исполнителя после резерва товара (Go)
Уровень: senior · Роль: backend · Категория: Технические вопросы
Компании: sferaplatform.ru
Стек: Go
> Пример ответа
Для гарантии, что заказ не будет выполнен без исполнителя после резерва товара, можно использовать распределённую блокировку (например, на основе Redis или etcd) в сочетании с транзакционной логикой. В Go это реализуется через паттерн «пессимистичная блокировка»: при резерве товара создаётся запись в БД со статусом «ожидает исполнителя» и временем жизни (TTL). Параллельно запускается фоновый воркер, который проверяет, назначен ли исполнитель до истечения TTL. Если исполнитель не назначен - резерв откатывается (товар возвращается на склад, заказ отменяется). Пример на Go с использованием Redis-блокировки и PostgreSQL:
GOfunc ReserveOrder(ctx context.Context, orderID string, ttl time.Duration) error {lockKey := "order:" + orderID + ":lock"lock, err := redisClient.SetNX(ctx, lockKey, "reserved", ttl).Result()if err != nil || !lock {return fmt.Errorf("order already reserved or error: %w", err)}defer redisClient.Del(ctx, lockKey)tx, _ := db.BeginTx(ctx, nil)defer tx.Rollback()// Резервируем товар_, err = tx.ExecContext(ctx, "UPDATE products SET reserved = TRUE WHERE id = $1 AND reserved = FALSE", productID)if err != nil {return err}// Создаём заказ со статусом "ожидание исполнителя"_, err = tx.ExecContext(ctx, "INSERT INTO orders (id, status, reserved_until) VALUES ($1, 'pending', NOW() + $2)", orderID, ttl)if err != nil {return err}return tx.Commit()}// Фоновый воркерfunc CleanupExpiredReservations(ctx context.Context) {for {rows, _ := db.QueryContext(ctx, "SELECT id FROM orders WHERE status = 'pending' AND reserved_until < NOW()")for rows.Next() {var orderID stringrows.Scan(&orderID)// Отмена заказа и возврат товараdb.ExecContext(ctx, "UPDATE orders SET status = 'cancelled' WHERE id = $1", orderID)db.ExecContext(ctx, "UPDATE products SET reserved = FALSE WHERE order_id = $1", orderID)}time.Sleep(10 * time.Second)}}
Также стоит добавить вебхук или событие в очередь (например, RabbitMQ) при назначении исполнителя, чтобы воркер мог немедленно снять блокировку. Это исключает гонки и гарантирует, что заказ не «зависнет» без исполнителя.
> Похожие задачи по backend
Как реализовать эффективную пагинацию с курсорами и индексами
Напиши функцию на Go, которая принимает слайс каналов int и возвращает канал с суммами чисел из каждого канала
Как снять бронь товара при отмене заказа
Как обрабатывать ошибки при отмене брони на складе
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью