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,33 @@
|
||||
---
|
||||
name: RateLimitConfig
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
algebraic: product
|
||||
definition: |
|
||||
type RateLimitConfig struct {
|
||||
RequestsPerSecond float64
|
||||
BurstSize int
|
||||
KeyFunc func(r *http.Request) string
|
||||
CleanupInterval time.Duration
|
||||
}
|
||||
description: "Configuracion declarativa para construir un rate limiter HTTP. Agrupa tasa sostenida, rafaga maxima, extractor de clave y frecuencia de GC."
|
||||
tags: [rate_limit, config, http, middleware, infra]
|
||||
uses_types: []
|
||||
file_path: "functions/infra/rate_limiter.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
cfg := RateLimitConfig{
|
||||
RequestsPerSecond: 10,
|
||||
BurstSize: 20,
|
||||
KeyFunc: func(r *http.Request) string { return r.Header.Get("X-API-Key") },
|
||||
CleanupInterval: 5 * time.Minute,
|
||||
}
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Estructura inmutable que parametriza un limiter. `KeyFunc` nil indica usar la IP del cliente. `CleanupInterval` 0 desactiva el GC automatico. El consumidor decide como inicializar el limiter a partir de esta config.
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: RateLimitResult
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
algebraic: product
|
||||
definition: |
|
||||
type RateLimitResult struct {
|
||||
Allowed bool
|
||||
Remaining int
|
||||
ResetAt time.Time
|
||||
RetryAfter float64
|
||||
}
|
||||
description: "Resultado de evaluar un request contra un RateLimiter. Indica si pasa, cuantos tokens quedan, cuando se rellena el bucket y cuanto esperar antes de reintentar."
|
||||
tags: [rate_limit, result, http, middleware, infra]
|
||||
uses_types: []
|
||||
file_path: "functions/infra/rate_limiter.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
result := RateLimiterCheck(rl, "192.168.1.1")
|
||||
if result.Allowed {
|
||||
// procesar request
|
||||
} else {
|
||||
w.Header().Set("Retry-After", strconv.FormatFloat(result.RetryAfter, 'f', 1, 64))
|
||||
}
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Snapshot inmutable del estado del bucket en el momento del check. `Remaining` es el numero entero de tokens disponibles tras el check. `ResetAt` es absoluto (UTC). `RetryAfter` es 0 cuando el request es permitido. Se serializa indirectamente a headers HTTP via `RateLimitHeaders`.
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: RateLimiter
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
algebraic: product
|
||||
definition: |
|
||||
type RateLimiter struct {
|
||||
rate float64
|
||||
burst int
|
||||
mu sync.Mutex
|
||||
clients map[string]*rateLimiterClient
|
||||
}
|
||||
description: "Token-bucket rate limiter in-memory. Mantiene un bucket por clave (IP o custom) con tokens recargados a tasa constante. Protegido por mutex para uso concurrente."
|
||||
tags: [rate_limit, http, middleware, token_bucket, infra]
|
||||
uses_types: []
|
||||
file_path: "functions/infra/rate_limiter.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
// 10 req/s con rafagas hasta 20
|
||||
rl := RateLimiterNew(10, 20)
|
||||
result := RateLimiterCheck(rl, "192.168.1.1")
|
||||
if !result.Allowed {
|
||||
// rechazar request
|
||||
}
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Tipo producto con estado mutable (mapa de clientes). Los campos son privados — se accede via `RateLimiterNew`, `RateLimiterCheck`, `RateLimiterCleanup`. El bucket se llena a `rate` tokens/segundo hasta un maximo de `burst`. Cada request consume 1 token. Sin GC explicito (`RateLimiterCleanup`) los buckets crecen indefinidamente con cada IP unica vista.
|
||||
Reference in New Issue
Block a user