Skip to main content

max / makenotwork

server: size-bound the idempotency negative cache (ultra-fuzz Run #1 Perf LOW) NEG_CACHE swept only every ~1024 misses, so a flood of unique idempotency keys (each missing once) could sit up to 1024-deep between sweeps. Add a hard 8192-entry size trigger alongside the tick so memory is bounded regardless of tick phase. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-19 21:30 UTC
Commit: 65bfa70bc75bfd4955f93c97c1584c3eb7006b18
Parent: fe2aeea
1 file changed, +8 insertions, -3 deletions
@@ -323,10 +323,15 @@ pub async fn idempotency_middleware(
323 323 .map(|e| e.elapsed().as_secs() < NEG_TTL_SECS)
324 324 .unwrap_or(false);
325 325
326 - // Periodic GC to keep the map bounded under sustained burst (every ~1k
327 - // misses we walk the map and drop expired entries).
326 + // Periodic GC to keep the map bounded: sweep every ~1k misses, OR whenever
327 + // the map exceeds a hard size cap. The tick alone let a flood of unique
328 + // keys (each missing exactly once) sit up to 1024-deep between sweeps; the
329 + // size trigger bounds memory under that pattern regardless of tick phase
330 + // (ultra-fuzz Run #1 Perf LOW).
331 + const NEG_CACHE_MAX_ENTRIES: usize = 8192;
328 332 static GC_TICK: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
329 - if GC_TICK.fetch_add(1, std::sync::atomic::Ordering::Relaxed).is_multiple_of(1024) {
333 + let tick = GC_TICK.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
334 + if tick.is_multiple_of(1024) || neg_cache.len() > NEG_CACHE_MAX_ENTRIES {
330 335 neg_cache.retain(|_, t| t.elapsed().as_secs() < NEG_TTL_SECS);
331 336 }
332 337