feat(infra): rate limiter token-bucket in-memory + tipos y core funcs
Implementa fase 1 del issue 0016: - Tipos RateLimiter, RateLimitConfig y RateLimitResult en types/infra/ - rate_limiter_new: constructor con validacion rate/burst > 0 - rate_limiter_check: evalua token bucket por key, calcula Allowed/Remaining/ResetAt/RetryAfter - rate_limit_headers (pure): construye headers IETF X-RateLimit-* y Retry-After - rate_limiter_cleanup: goroutine GC de entries inactivas con stop idempotente Sin dependencias externas (no Redis). sync.Mutex + map. Algoritmo token bucket estandar con recarga lineal proporcional al tiempo transcurrido.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package infra
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// rateLimiterClient mantiene el estado de un bucket para una clave concreta.
|
||||
type rateLimiterClient struct {
|
||||
tokens float64
|
||||
lastSeen time.Time
|
||||
}
|
||||
|
||||
// RateLimiter mantiene el estado token-bucket de todos los clientes en memoria.
|
||||
// rate son los tokens recargados por segundo, burst es la capacidad maxima del bucket.
|
||||
// El campo clients es un mapa key -> bucket protegido por mu.
|
||||
type RateLimiter struct {
|
||||
rate float64
|
||||
burst int
|
||||
mu sync.Mutex
|
||||
clients map[string]*rateLimiterClient
|
||||
}
|
||||
|
||||
// RateLimitConfig parametriza el middleware de rate limiting.
|
||||
// KeyFunc extrae la clave del request (nil = IP del cliente).
|
||||
// CleanupInterval controla la frecuencia del GC de entries inactivas (0 = no GC).
|
||||
type RateLimitConfig struct {
|
||||
RequestsPerSecond float64
|
||||
BurstSize int
|
||||
KeyFunc func(r *http.Request) string
|
||||
CleanupInterval time.Duration
|
||||
}
|
||||
|
||||
// RateLimitResult es el resultado de evaluar un request contra el limiter.
|
||||
// Allowed indica si el request puede pasar.
|
||||
// Remaining son los tokens restantes en el bucket despues del check.
|
||||
// ResetAt es el momento en que el bucket vuelve a estar lleno.
|
||||
// RetryAfter son los segundos hasta que se pueda reintentar (0 si Allowed).
|
||||
type RateLimitResult struct {
|
||||
Allowed bool
|
||||
Remaining int
|
||||
ResetAt time.Time
|
||||
RetryAfter float64
|
||||
}
|
||||
Reference in New Issue
Block a user