Políticas reutilizables con definePolicy
definePolicy agrupa los mismos operadores funcionales de resiliencia en una configuración inmutable y validada, que puedes reutilizar en múltiples pipelines o extender en nuevas políticas derivadas.
Importación
Sección titulada «Importación»import { definePolicy } from 'annotations-design-patterns/policy';import { pipe } from 'annotations-design-patterns/pipe';Sintaxis básica
Sección titulada «Sintaxis básica»const profilePolicy = definePolicy<Receiver, Args, Return>({ fallback: { value: defaultValue }, circuitBreaker: { failures: 3, resetMs: 5_000 }, retry: { attempts: 3, delayMs: 100, idempotent: true }, timeout: { ms: 1_000 },});Solo activas las capas que necesitas. Las que faltan o false se desactivan.
Orden por defecto
Sección titulada «Orden por defecto»Las capas se ejecutan en este orden (de afuera hacia adentro):
- fallback — más externo, atrapa y retorna valor
- circuitBreaker — frena tras fallos
- retry — reintenta
- timeout — más interno (limita tiempo)
Es el orden más lógico para resiliencia: si todo falla, el fallback lo atrapa.
Ejemplo completo
Sección titulada «Ejemplo completo»const profilePolicy = definePolicy<object, readonly [id: string], string>({ fallback: { value: 'unavailable' }, circuitBreaker: { failures: 3, resetMs: 5_000 }, retry: { attempts: 3, delayMs: 100, idempotent: true }, timeout: { ms: 1_000 },});
const loadProfile = pipe( async (id: string) => fetchProfile(id), profilePolicy.operator(),);
// Úsaloconst profile = await loadProfile.call({}, '42');Extender una política
Sección titulada «Extender una política»Usa .extend() para crear una nueva política con opciones sobrescritas:
const stricterPolicy = profilePolicy.extend({ retry: { attempts: 5, delayMs: 50, idempotent: true }, timeout: { ms: 500 },});
const strictLoad = pipe(fetchProfile, stricterPolicy.operator());La política original no cambia — .extend() retorna una nueva.
Validación
Sección titulada «Validación»definePolicy valida la configuración antes de la primera invocación:
retryexigeidempotent: true— las politicas de reintento sin garantía de idempotencia se rechazan conInvalidPolicyError.- Combinaciones peligrosas se detectan — p. ej. una política que no puede garantizar correctitud lanza error al compilarla, no al ejecutarla.
Capas disponibles
Sección titulada «Capas disponibles»fallback: { value: T | () => T }— Valor o función que retorna respaldocircuitBreaker: { failures: number, resetMs: number }— Abre tras N fallos consecutivosretry: { attempts: number, delayMs?: number, backoffFactor?: number, idempotent: boolean }— Reintentos con backofftimeout: { ms: number }— Límite de tiempo
Todas son opcionales. Pasa false para desactivar una capa específica:
const noRetry = profilePolicy.extend({ retry: false });Métodos de PolicyDefinition
Sección titulada «Métodos de PolicyDefinition»operator()
Sección titulada «operator()»Retorna un operador funcional para usar en pipe:
const pipeline = pipe(method, policy.operator());extend(overrides)
Sección titulada «extend(overrides)»Retorna una nueva política con cambios:
const derived = policy.extend({ retry: { attempts: 5, idempotent: true } });describe() (avanzado)
Sección titulada «describe() (avanzado)»Genera una descripción textual de la política (útil para logs):
console.log(policy.describe());// "Fallback('unavailable') → CircuitBreaker(3/5000ms) → Retry(3x) → Timeout(1000ms)"Para tipos y opciones avanzadas
Sección titulada «Para tipos y opciones avanzadas»Consulta la Referencia de policy.

