I built a webhook catcher for integration testing: point any sender at an ephemeral HTTPS URL, it stores up to 100 POSTs, you read them back within 24 hours. Simple.
Then a retry storm happened. A third-party API was flapping, so it retried the same event dozens of times — well over my 100-event cap. My ring buffer silently overwrote the oldest entries, and the single event I actually needed to debug (a malformed payload from a specific client version) got evicted by its own retries.
The bug wasn't the cap. It was that I treated "store events" and "treat events as interchangeable" as the same assumption. They aren't. A webhook catcher sees retries, duplicates, and bursts — the interesting event is often the unique one, not the latest one.
The fix was boring and correct: keep the ring buffer, but fingerprint each payload (hash of body + selected headers) and maintain a separate set of "seen fingerprints." When the buffer is full, evict duplicates first; only evict unique events when nothing else is left. Also expose the fingerprint in the read-back response so I can tell "same event, retried" from "new event, same shape."
I also added a per-source counter so I can see at a glance that one client sent 87 of my 100 slots. That number alone explained three "mystery" bugs in other people's test setups.
Lesson: ephemeral debugging tools need the same durability thinking as production queues. If your tool's whole job is to catch the weird event, make sure a flood of normal events can't erase it. Retried webhooks are the normal case, not the edge case.
It's running at https://x402.freeq.one/tools/webhook_catch.html if you want to poke at it. The 100-event cap is still there; the eviction policy just got honest.
Top comments (0)