Declaraciones públicas de zig/src/replay.zig (spire-zig (SDK consumido)).
apps/docs/generated/zig/spire.jsonPágina generada desde
spire@spire-0.2.0-XvnrRek1BgCX4Bh8miuITCQgkn0FqeQrYYE3goFfDcQd (zig/src/root.zig). No se edita a mano:bun run docs:genla regenera ybun run docs:checkfalla si difiere.
Anti-replay de sobres (dec-0119 §5.3).
ts_ms tiene que caer en now ± window_ms; fuera es Stale o
FromFuture.(source, nonce) se recuerda mientras el sobre podría admitirse
(ts + window). Visto otra vez:
· con el mismo id → duplicate: redelivery legítima de JetStream o
reintento del cliente con los mismos bytes; el llamador responde con
la respuesta cacheada o status = duplicate, sin re-ejecutar.
· con otro id → Replayed: alguien reutiliza el nonce. Se audita.source sólo puede tener vivas las entradas
que le reserva reserve (lo que su rate admitido mete en una ventana).
Una fuente que inunda agota su cuota (ReplayCacheFull para ella),
nunca la de otra. Una fuente sin reserva no entra (cuota 0).reserve (al registrar los handlers) reserva la suma de
las cuotas; check no asigna. Llena de entradas vivas rechaza en vez de
olvidar (olvidar abriría el replay).Thread-safe (un mutex). La caché es local al proceso: vale para unix e
inproc; con varias réplicas consumiendo el mismo subject NATS hace falta
la variante compartida (Valkey) del lado TS (ADR del SDK §5).
replay.Verdicttype · línea 27
pub const Verdict = enumSin ///.
replay.Errorconst · línea 29
pub const Error = error{ Stale, FromFuture, Replayed, ReplayCacheFull }Sin ///.
replay.ReserveErrorconst · línea 31
pub const ReserveError = error{ ReplayBudgetTooLarge, TooManySources } || std.mem.Allocator.ErrorSin ///.
replay.Optionstype · línea 33
pub const Options = structSin ///.
replay.max_sourcesconst · línea 45
pub const max_sources = 64Fuentes distintas por guard (las identidades de un keyring).
replay.quotafn · línea 51
pub fn quota(opts: Options, per_sec: u32, burst: u32) u64Entradas de la caché que un rate per_sec/burst mete en una ventana con
las opciones opts: burst + ⌈per_sec × (window_ms + prune_interval_ms) / 1000⌉.
Para dimensionar max_entries: la suma de esto por cada (emisor, ruta)
que admite el router.
replay.BudgetReporttype · línea 57
pub const BudgetReport = structDatos de un reserve que no cabe.
replay.BudgetReport.sourcefn · línea 77
pub fn source(self: *const BudgetReport) []const u8Primera fuente de la llamada que ya no cabe.
replay.BudgetReport.formatfn · línea 81
pub fn format(self: BudgetReport, w: *std.Io.Writer) std.Io.Writer.Error!voidSin ///.
replay.ReplayGuardtype · línea 120
pub const ReplayGuard = structSin ///.
replay.ReplayGuard.initfn · línea 135
pub fn init(allocator: std.mem.Allocator, opts: Options) ReplayGuardSin ///.
replay.ReplayGuard.deinitfn · línea 139
pub fn deinit(self: *ReplayGuard) voidSin ///.
replay.ReplayGuard.quotaForfn · línea 148
pub fn quotaFor(self: *const ReplayGuard, per_sec: u32, burst: u32) u64Entradas que caben en una ventana a per_sec con ráfaga burst
(más el intervalo de poda) con las opciones de este guard.
replay.ReplayGuard.reservefn · línea 155
pub fn reserve(self: *ReplayGuard, source: []const u8, per_sec: u32, burst: u32) ReserveError!voidReserva para source lo que un rate per_sec/burst admite en una
ventana; se acumula (una fuente en varias rutas suma cada una). Se
llama al registrar (asigna); check después no asigna.
replay.ReplayGuard.reserveAllfn · línea 163
pub fn reserveAll(self: *ReplayGuard, sources: []const []const u8, per_sec: u32, burst: u32) ReserveError!voidreserve de todas las sources a la vez: o se reservan todas o
ninguna (una ruta que no cabe no deja cuota reservada a medias).
Si no cabe, last_budget_error dice qué fuente, cuánto pedía y
cuánto quedaba (el router lo registra en el log con el subject).
replay.ReplayGuard.lastBudgetErrorfn · línea 205
pub fn lastBudgetError(self: *ReplayGuard) ?BudgetReportCopia, bajo el mutex, del informe del último reserveAll.
replay.ReplayGuard.checkfn · línea 260
pub fn check(self: *ReplayGuard, source: []const u8, id: envelope.Id, nonce: envelope.Nonce, ts_ms: u64, now_ms: u64) Error!VerdictSin ///.
replay.ReplayGuard.countfn · línea 295
pub fn count(self: *ReplayGuard) usizeSin ///.
replay.ReplayGuard.quotaOffn · línea 302
pub fn quotaOf(self: *ReplayGuard, source: []const u8) u32Cuota reservada para source (0 si no tiene).