Commit Graph

2 Commits

Author SHA1 Message Date
cd34e52064 build: update golangci-lint to v2.12.2 with new canonical v2 config
All checks were successful
check / check (push) Successful in 31s
Pin golangci-lint to commit c0d3ddc9cf3faa61a4e378e879ece580256d76e5
(v2.12.2) in Dockerfile and script/bootstrap.

Replace .golangci.yml with a v2-schema migration of the canonical
config, produced with golangci-lint migrate (owner-authorized; the
same file becomes the new org-wide canonical via a prompts-repo PR).
Lint settings now live under linters.settings, so the lll, funlen,
cyclop, and dupl thresholds are actually applied. The deprecated
gomodguard linter is disabled in favor of gomodguard_v2, resolving
the v2.12 deprecation warning. Deliberate delta from the migrate
output: the gci formatter is not enabled because its default two-group
import ordering conflicts with the repo's stdlib/third-party/local
import style that script/fmt (gofmt + goimports) produces.

Fix all findings surfaced by the now-active thresholds:

- goconst: shared constants for repeated status, priority, and DNS
  fixture strings in watcher.go and the notify, state, and watcher
  tests
- dupl: consolidate duplicated ntfy/slack HTTP-error tests and
  SendNotification endpoint-error tests behind shared helpers
- lll: wrap long test table entries and comments; shorten one inline
  nolint justification
2026-08-07 20:38:01 +00:00
23f115053b feat: add retry with exponential backoff for notification delivery (#87)
All checks were successful
check / check (push) Successful in 37s
## Summary

Notifications were fire-and-forget: if Slack, Mattermost, or ntfy was temporarily down, changes were silently lost. This adds automatic retry with exponential backoff and jitter to all notification endpoints.

## Changes

### New file: `internal/notify/retry.go`
- `RetryConfig` struct with configurable max retries, base delay, max delay
- `backoff()` computes delay as `BaseDelay * 2^attempt`, capped at `MaxDelay`, with ±25% jitter
- `deliverWithRetry()` wraps any send function with the retry loop
- Defaults: 3 retries (4 total attempts), 1s base delay, 10s max delay
- Context-aware: respects cancellation during retry sleep
- Injectable `sleepFn` for test determinism

### Modified: `internal/notify/notify.go`
- Added `retryConfig` and `sleepFn` fields to `Service`
- Updated `dispatchNtfy`, `dispatchSlack`, `dispatchMattermost` to wrap sends in `deliverWithRetry`
- Structured logging: warns on each retry, logs error only after all retries exhausted, logs info on success after retry

### Modified: `internal/notify/export_test.go`
- Added test helpers: `SetRetryConfig`, `SetSleepFunc`, `DeliverWithRetry`, `BackoffDuration`

### New file: `internal/notify/retry_test.go`
- Backoff calculation tests (exponential increase, max cap with jitter)
- `deliverWithRetry` unit tests: first-attempt success, transient failure recovery, exhausted retries, context cancellation
- Integration tests via `SendNotification`: transient failure retries, all-endpoints retry independently, permanent failure exhausts retries

## Verification
- `make fmt` 
- `make check` (format + lint + tests + build) 
- `docker build .` 
- All existing tests continue to pass unchanged
- No DNS client mocking — notification tests use `httptest` servers

closes #62

Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #87
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-22 07:14:59 +01:00