> Как гарантировать, что заказ не будет выполнен без исполнителя после резерва товара (Go)

Уровень: senior · Роль: backend · Категория: Технические вопросы

Компании: sferaplatform.ru

Стек: Go

> Пример ответа

Для гарантии, что заказ не будет выполнен без исполнителя после резерва товара, можно использовать распределённую блокировку (например, на основе Redis или etcd) в сочетании с транзакционной логикой. В Go это реализуется через паттерн «пессимистичная блокировка»: при резерве товара создаётся запись в БД со статусом «ожидает исполнителя» и временем жизни (TTL). Параллельно запускается фоновый воркер, который проверяет, назначен ли исполнитель до истечения TTL. Если исполнитель не назначен - резерв откатывается (товар возвращается на склад, заказ отменяется). Пример на Go с использованием Redis-блокировки и PostgreSQL:

GO
func 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 string
rows.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) при назначении исполнителя, чтобы воркер мог немедленно снять блокировку. Это исключает гонки и гарантирует, что заказ не «зависнет» без исполнителя.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью