Files
fn_registry/functions/infra/rate_limit_headers.go
egutierrez 036c0a8d63 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.
2026-04-18 17:11:22 +02:00

28 lines
896 B
Go

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
}