perf: throttle replay-cache pruning to once per second
ober
fc98c0e640f805092cba278cdd70dc08b7d15757
--- a/edge.ss +++ b/edge.ss @@ -692,6 +692,17 @@ *replay-keys*) (for-each (lambda (key) (hash-remove! *replay-keys* key)) expired))) +;; Pruning scans the whole replay cache, so doing it on every claim made +;; webhook throughput O(n) per request (O(n^2) at rate) under the mutex. +;; Throttle it to at most once per second; expired keys linger briefly, which +;; only nudges the capacity check. Caller holds *replay-mutex*. +(def *last-replay-prune-second* 0) + +(def (%maybe-prune-replay-keys! now) + (when (>= (- now *last-replay-prune-second*) 1) + (set! *last-replay-prune-second* now) + (%prune-replay-keys! now))) + (def (claim-replay-key! source event-id nonce timestamp) (let* ([now (time-second (current-time))] [expires (+ now *replay-window-seconds*)] @@ -704,7 +715,7 @@ (string->utf8 (string-append "nonce\n" source "\n" nonce))))]) (with-mutex *replay-mutex* - (%prune-replay-keys! now) + (%maybe-prune-replay-keys! now) (cond [(or (hash-key? *replay-keys* event-key) (hash-key? *replay-keys* nonce-key)) #f]