Un efecto bajo presupuesto es un recurso lineal — ninguna emisión sin presupuesto (v2.28.0)
Un limitador de tasa atornillado al lado de un programa —un cubo de tokens en
Redis dentro de un middleware, un estrangulador de Sidekiq, un pool de Airflow—
es invisible para el sistema de tipos y para el propio razonamiento del
programa. El programa cree que puede llamar a una herramienta; un contador
externo, en otro sitio, a veces dice que no. La v2.28.0 mete ese contrato DENTRO
del lenguaje: un efecto bajo un budget es un recurso lineal que el compilador
ve y que el runtime coimpone.
La ley. Un efecto externo declarado bajo un
budget { … on Tool(X) }es un recurso lineal. El runtime no puede emitirlo sin consumir un token; la sobreemisión es imposible por construcción. Token presente ⇒ adelante (consumir); token ausente ⇒block/defer/shedsegúnon_exhausted— nunca una emisión por encima del presupuesto.
Por qué es lineal (la disciplina afín, con recarga)
El kernel de lease/reconcile ya implementa recursos afines para manejadores
dentro de un flow: un LeaseToken es de un solo uso y decae a lo largo de τ —
lo adquieres y es tuyo hasta que expira, y entonces desaparece. La v2.28.0
generaliza ese token a un RateLease para efectos externos:
- Una cuota
rate:es un cubo de tokens de capacidadlimitque se recarga conlimittokens por periodo (de forma continua,limit/periodpor segundo). Permite una ráfaga de hastalimity después un ritmo constante. Se recarga, pero está acotada — nunca más delimiten vuelo. - Una cuota
max:es una ventana fija: como mucholimitconsumos por periodo, y el contador solo se reinicia cuando la ventana rueda. Un tope duro, sin recarga dentro de la ventana.
Las dos mantienen la invariante de linealidad que tiene el token afín: un token consumido no está hasta que se recargue. La diferencia con el token de lease es solo la recarga —de un solo uso pasa a N usos—, no la disciplina. Es el mismo álgebra afín del pilar de Lógica, aplicada en la frontera donde el programa toca el mundo en vez de en un manejador interno.
Por qué es determinista
Una decisión de presupuesto es una función pura. Los tokens disponibles del cubo
son min(capacity, prior + elapsed × rate); la disponibilidad de la ventana es
limit − consumed, y rueda cuando now − window_start ≥ period. La recarga es
PEREZOSA —se calcula desde el tiempo de reloj transcurrido en cada adquisición—,
así que el veredicto nunca depende de la granularidad de un tick de fondo. Dado
el mismo (estado del cubo, now), acquire produce la misma concesión o
denegación, y el mismo estado posterior, bit a bit. Cada concesión y cada
denegación son, por tanto, reproducibles y auditables: una llamada por encima del
presupuesto no falló "probablemente" — se puede demostrar que nunca llegó a
emitirse.
Las políticas de agotamiento — todas honestas
Cuando no hay token, el on_exhausted del daemon decide, dentro de un catálogo
cerrado:
block(el valor por defecto, que falla cerrado) — el step falla con el tipadoEffectQuotaExhausted(axon-E0810). La llamada no se emite.defer— el tick se reprograma al primer instante en que se libere un token (EffectDeferred,axon-E0811), reutilizando el ledger de aplazamientos fusionados de la v2.27.0. El trabajo se conserva, ni se pierde ni se sobreemite.shed— al mejor esfuerzo: la llamada se salta, el flow continúa y el salto queda auditado (effect:shed) — nunca en silencio.
Ninguna de las tres emite por encima del presupuesto. Solo se diferencian en qué le pasa al resto del trabajo, no en si el presupuesto se sostiene.
Qué prohíbe esto
- Ninguna emisión sin presupuesto. Una herramienta bajo un
budgetno puede llamarse sin un token. No hay ningún camino en el despachador que emita el efecto esquivando la compuerta. - Nada de limitación meramente orientativa. El presupuesto no es un contador que el programa pueda consultar e ignorar; la compuerta de despacho consume o deniega antes del efecto, así que el límite es estructural, no una sugerencia.
- Ningún exceso silencioso con una sola réplica. El kernel en proceso es exacto. (El enlace multirréplica de la edición enterprise es honesto sobre su cota —como mucho N, con una pequeña ventana de exceso, y falla abierto ante un error de Redis— y lo dice; no afirma una entrega distribuida exactamente-una-vez que no puede cumplir.)
Relación con las demás leyes
- Generaliza la disciplina afín del kernel de lease, de los manejadores dentro de un flow a los efectos externos — la misma linealidad, ahora en la frontera.
- Es la hermana en tasa de efectos de
time_is_an_explicit_input: esa ley hace que cuándo se ejecuta un efecto sea una función pura de entradas registradas; esta hace que con qué frecuencia puede ejecutarse sea un recurso lineal. Undaemonque declara a la vez unawindowy unbudgettiene su temporización Y su tasa coimpuestas, de forma determinista. - Lleva el espíritu de
no_unwitnessed_advantage: allí, ninguna afirmación sin un testigo comprobable por máquina; aquí, ninguna emisión sin un token consumido — y la pruebaEffectBudgetedde la v2.28.0 convierte la solidez del presupuesto en un objeto verificable de forma independiente.
La prueba honesta: si tu límite de tasa vive al lado del programa y el programa no puede razonar sobre él, tus efectos no son lineales — son esperanzadamente acotados. AXON convierte el presupuesto en un recurso que el programa tiene en la mano y que el runtime no puede gastar de más.