Skip to content

Stamp webhook rate limiter only on successful delivery - #88

Merged
LarsLaskowski merged 1 commit into
mainfrom
claude/issue-62-h4izt2
Aug 17, 2026
Merged

Stamp webhook rate limiter only on successful delivery#88
LarsLaskowski merged 1 commit into
mainfrom
claude/issue-62-h4izt2

Conversation

@LarsLaskowski

@LarsLaskowski LarsLaskowski commented Aug 17, 2026

Copy link
Copy Markdown
Owner

📖 Description

rateLimited (internal/alert/notify.go) stamped lastSent[key] = ev.At at
check time, before deliver ran. If that delivery then failed all retries,
the next firing of the same metric within notify_min_interval_seconds was
still suppressed as a "repeat" — even though nothing was ever delivered.

The fix splits the check from the stamp: rateLimited now only reads
lastSent, and a new recordSent is called from dispatch only after
deliver reports the delivery ultimately succeeded. deliver now returns a
bool for that purpose instead of void.

This is a fix, not a breaking change; no config or API shape changes.

🎫 Issues

Closes #62

👩‍💻 Reviewer Notes

The core change is small: deliver gained a bool return value, and the
rate-limit stamping moved out of rateLimited into a new recordSent
helper called from dispatch only on success. lastSent is still only
touched by the single worker goroutine, so no locking changes were needed.

📑 Test Plan

Added TestNotifier_RateLimitDoesNotCountFailedDelivery in
internal/alert/notify_test.go: an event delivery that fails (500 response,
0 retries) must not stamp the rate limiter, so a second firing of the same
metric 1s later — deep inside a 60s rate-limit window — is still delivered
once the endpoint recovers. Verified this test fails on the pre-fix code
(the second event gets dropped as rate-limited) and passes with the fix.

Ran locally:

  • go build ./...
  • go vet ./...
  • go test ./... -race -cover (all packages pass; internal/alert at 92.8%
    coverage)
  • golangci-lint run (0 issues)

✅ Checklist

General

  • I have added/updated tests for my changes (go test ./... -race -cover passes locally).
  • go vet ./... and golangci-lint run are clean.
  • I have tested my changes.
  • I have read the CONTRIBUTING documentation and followed the project's code style guidelines.
  • I have updated ARCHITECTURE.md if this changes a documented design decision. (not applicable — internal robustness fix, no design change)

REST API / configuration / packaging

Not applicable — no REST API, configuration, or packaging changes.

⏭ Next Steps

None.

rateLimited previously recorded lastSent[key] at check time, before
deliver() ran. If that delivery then failed all retries, the next
firing of the same metric within notify_min_interval_seconds was
still suppressed as a "repeat" even though nothing was ever
delivered.

Split the stamp out of the check: rateLimited() now only reads
lastSent, and dispatch() calls the new recordSent() after deliver()
reports success. deliver() now returns whether it ultimately
succeeded so dispatch() can make that call.

Closes #62
@sonarqubecloud

Copy link
Copy Markdown

@LarsLaskowski
LarsLaskowski merged commit 21a7a33 into main Aug 17, 2026
5 checks passed
@LarsLaskowski
LarsLaskowski deleted the claude/issue-62-h4izt2 branch August 17, 2026 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Robustness: webhook rate limiter records a delivery before it succeeds

2 participants