RateLimiter - sebamar88/bytekit GitHub Wiki

🚦 RateLimiter

EN: URL-based rate limiting with two implementations: Token Bucket (burst-friendly) and Sliding Window (precise). Prevents overwhelming APIs by tracking requests per URL hostname.

ES: Limitación de tasa basada en URL con dos implementaciones: Token Bucket (permite ráfagas) y Sliding Window (preciso). Previene sobrecargar APIs rastreando solicitudes por hostname de URL.


📦 Import

import { RateLimiter, SlidingWindowRateLimiter } from "bytekit/rate-limiter";
// or | o también:
import { RateLimiter, SlidingWindowRateLimiter } from "bytekit";

⚙️ Constructor

const limiter = new RateLimiter(config?: RateLimiterConfig);
const limiter = new SlidingWindowRateLimiter(config?: RateLimiterConfig);

RateLimiterConfig

Property / Propiedad Type / Tipo Default Description (EN) Descripción (ES)
maxRequests number 100 Max requests allowed in the window Máximo de solicitudes permitidas en la ventana
windowMs number 60000 Time window in milliseconds (1 min) Ventana de tiempo en milisegundos (1 min)
keyGenerator (url: string) => string url => new URL(url).hostname Function to derive the rate-limit key from a URL Función para derivar la clave de rate-limit de una URL

📋 Methods / Métodos

EN: Both RateLimiter and SlidingWindowRateLimiter share the same methods.

ES: Tanto RateLimiter como SlidingWindowRateLimiter comparten los mismos métodos.

Method / Método Signature / Firma Description (EN) Descripción (ES)
isAllowed isAllowed(url: string): boolean Checks if a request to this URL is allowed Verifica si una solicitud a esta URL está permitida
getStats getStats(url: string): RateLimiterStats Returns stats for a URL Devuelve estadísticas para una URL
reset reset(url: string): void Resets the limit for a specific URL Reinicia el límite para una URL específica
resetAll resetAll(): void Resets all rate limits Reinicia todos los límites
waitForAllowance waitForAllowance(url: string): Promise<void> Waits (blocks) until a request is allowed Espera (bloquea) hasta que una solicitud sea permitida

RateLimiterStats

interface RateLimiterStats {
  remaining: number;   // Requests remaining in the window / Solicitudes restantes en la ventana
  limit: number;       // Max requests per window / Máximo de solicitudes por ventana
  resetAt: number;     // Timestamp when the window resets / Timestamp de reinicio de ventana
  retryAfter?: number; // Seconds to wait if limit exceeded / Segundos de espera si se excedió el límite
}

🧠 How They Differ / Cómo se Diferencian

Token Bucket (RateLimiter)

EN: Starts with a full "bucket" of tokens. Each request consumes one token. Tokens refill gradually over time. This allows bursts — you can use all tokens at once, then wait for refills.

ES: Comienza con un "cubo" lleno de tokens. Cada solicitud consume un token. Los tokens se rellenan gradualmente con el tiempo. Esto permite ráfagas — puedes usar todos los tokens de una vez, luego esperar recargas.

[████████████] 100 tokens  →  burst 20 requests  →  [████████░░░░] 80 remaining
                                                         ↓ time passes
                                                    [██████████░░] 90 remaining (refilled)

Sliding Window (SlidingWindowRateLimiter)

EN: Tracks exact timestamps of each request. Counts only requests within the last windowMs milliseconds. More precise but uses more memory because it stores every timestamp.

ES: Rastrea las marcas de tiempo exactas de cada solicitud. Cuenta solo solicitudes dentro de los últimos windowMs milisegundos. Más preciso pero usa más memoria porque almacena cada timestamp.

|--- windowMs (60s) ---|
[req][req][req]........[req]  →  count = 4  (within window)
  ↑ old requests expire as time passes / las solicitudes antiguas expiran con el tiempo

When to Use Each / Cuándo Usar Cada Uno

Scenario / Escenario Recommended / Recomendado
General-purpose API limiting RateLimiter (Token Bucket)
APIs with strict per-second limits SlidingWindowRateLimiter
Allow occasional bursts RateLimiter (Token Bucket)
Need precise counting SlidingWindowRateLimiter

💡 Examples / Ejemplos

Basic Token Bucket / Token Bucket Básico

import { RateLimiter } from "bytekit/rate-limiter";

const limiter = new RateLimiter({
  maxRequests: 10,
  windowMs: 60_000, // 10 requests per minute per hostname
});

const url = "https://api.example.com/users";

if (limiter.isAllowed(url)) {
  const res = await fetch(url);
  // ...
} else {
  const stats = limiter.getStats(url);
  console.log(`Rate limited. Retry in ${stats.retryAfter}s`);
}

Sliding Window / Ventana Deslizante

import { SlidingWindowRateLimiter } from "bytekit/rate-limiter";

const limiter = new SlidingWindowRateLimiter({
  maxRequests: 5,
  windowMs: 10_000, // 5 requests per 10 seconds
});

for (let i = 0; i < 8; i++) {
  const allowed = limiter.isAllowed("https://api.example.com/data");
  console.log(`Request ${i + 1}: ${allowed ? "✅ Allowed" : "❌ Blocked"}`);
}
// ✅ ✅ ✅ ✅ ✅ ❌ ❌ ❌

Wait for Allowance / Esperar Permiso

const limiter = new RateLimiter({ maxRequests: 2, windowMs: 5000 });

async function safeFetch(url: string) {
  // EN: Blocks until the rate limiter allows the request
  // ES: Bloquea hasta que el rate limiter permita la solicitud
  await limiter.waitForAllowance(url);
  return fetch(url);
}

Custom Key Generator / Generador de Claves Personalizado

// EN: Rate limit per full path, not just hostname
// ES: Limitar tasa por ruta completa, no solo hostname
const limiter = new RateLimiter({
  maxRequests: 30,
  windowMs: 60_000,
  keyGenerator: (url) => {
    const u = new URL(url);
    return `${u.hostname}${u.pathname}`;
  },
});

Checking Stats / Verificar Estadísticas

const stats = limiter.getStats("https://api.example.com/users");

console.log(`Remaining: ${stats.remaining}/${stats.limit}`);
console.log(`Resets at: ${new Date(stats.resetAt).toISOString()}`);
if (stats.retryAfter) {
  console.log(`Retry after: ${stats.retryAfter}s`);
}

⚠️ Important Notes / Notas Importantes

EN: Both rate limiters are URL-based — they group requests by the key derived from the URL (hostname by default). They do not limit by action type (GET vs POST). If you need per-action limits, use a custom keyGenerator that includes the HTTP method.

ES: Ambos rate limiters son basados en URL — agrupan solicitudes por la clave derivada de la URL (hostname por defecto). No limitan por tipo de acción (GET vs POST). Si necesitas límites por acción, usa un keyGenerator personalizado que incluya el método HTTP.


🔗 See Also / Véase También

  • RequestDeduplicator — Deduplicate concurrent identical requests / Deduplicar solicitudes idénticas concurrentes
  • RequestCache — Cache responses to reduce total requests / Cachear respuestas para reducir solicitudes totales
  • ApiClient — HTTP client for building resilient request pipelines / Cliente HTTP para construir pipelines de solicitudes resilientes
⚠️ **GitHub.com Fallback** ⚠️