Контекст: В backend/cmd/api/main.go:119 выбор между fail-open и fail-closed для Redis rate limiter определяется окружением: failOpen := cfg.AppEnv != "production".
// main.go:119
failOpen := cfg.AppEnv != "production"
Когда Redis недоступен:
Fail-closed (production): rate limiter возвращает 503. Сервис недоступен, но защищён.
graph TD
A[Redis timeout / connection error] --> B{failOpen?}
B -->|Yes - dev| C[In-Memory fallback]
B -->|No - production| D[503 Service Unavailable]
C --> E[Rate limiting weaker]
D --> F[Service blocked]
// ratelimit_redis.go:61-64
if r.failOpen {
next.ServeHTTP(w, req) // пропускаем запрос
return
}
Плюсы:
Минусы:
// ratelimit_redis.go:66-69
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusServiceUnavailable)
_, _ = w.Write([]byte(`{"error":"rate limiter unavailable"}`))
Плюсы:
Минусы:
/health) недоступенВариант: fallback на in-memory с более строгими лимитами в production (например, 10 req/min для всех эндпоинтов)
// Пример: fallback со строгими лимитами
if r.failOpen {
strictLimiter.Allow() // более строгий лимит для production fallback
next.ServeHTTP(w, req)
return
}
Ping + WarnContext)AppEnvCode review PhotoPlaces 2026-06. main.go:119.
#redis #rate-limiting #production #availability #security #architecture