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,27 @@
|
||||
package infra
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// RateLimitHeaders construye los headers IETF estandar de rate limiting a partir de un resultado.
|
||||
// Setea X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset y, si no esta permitido, Retry-After.
|
||||
// limit es la capacidad total (burst) que se anuncia al cliente.
|
||||
// Funcion pura — solo formatea, no hace I/O.
|
||||
func RateLimitHeaders(result RateLimitResult, limit int) http.Header {
|
||||
h := http.Header{}
|
||||
h.Set("X-RateLimit-Limit", strconv.Itoa(limit))
|
||||
h.Set("X-RateLimit-Remaining", strconv.Itoa(result.Remaining))
|
||||
h.Set("X-RateLimit-Reset", strconv.FormatInt(result.ResetAt.Unix(), 10))
|
||||
if !result.Allowed {
|
||||
// Retry-After segun RFC 7231: numero entero de segundos.
|
||||
retryAfter := int(math.Ceil(result.RetryAfter))
|
||||
if retryAfter < 1 {
|
||||
retryAfter = 1
|
||||
}
|
||||
h.Set("Retry-After", strconv.Itoa(retryAfter))
|
||||
}
|
||||
return h
|
||||
}
|
||||
Reference in New Issue
Block a user