ProcessEvents' safety-net poll was a bare time.Minute literal inline in its select statement - no way to verify the fallback path works without waiting 60+ seconds in a test, no way to tune the cadence without a code change, and no way to tell afterward whether a given loop iteration was triggered by a real NOTIFY or by the poll timer. Adds Mocks.pollInterval (default time.Minute) and a WithPollInterval(d) builder, mirroring WithNotifyRetryAfter's existing pattern - deploy-time configurable via construction, not a live/API-adjustable knob, and not wired through .env, matching how notifyRetryAfter already works. Adds a Debug log line on each of the two meaningful wake-up branches so which path fired is now observable. New test proves the poll branch actually works without waiting or touching the shared DB trigger (which would be unsafe against the real dev DB): it reuses the retry mechanism from the previous commit so a second dispatch can only come from the poll timer, since nothing else ever notifies again for the rest of the test. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEDaCB7C2NEBgyvqEtZuxY
3.5 KiB
3.5 KiB
Work Summary — 2026-08-05 21:01
Task
Insight #3 from the domains/amazon design review: the 1-minute poll fallback in ProcessEvents was a bare time.Minute literal inline in a select - untestable without waiting 60+ seconds or refactoring, not tunable without a code change, and with no logging distinguishing whether a wake-up came from a real NOTIFY or the poll timer.
Design confirmed with user before implementing
- Deploy-time configurable, not live/API-adjustable - matches how
notifyRetryAfter(insight #2) already works: a field set once atMocksconstruction, changed by editing the call site and restarting, not a runtime toggle. No stated need for a live knob, and adding one (mutex-guarded field, endpoint, auth, validation) would be real complexity for a need nobody has. - Go-level field + builder only, not wired through
.env/config.Config- consistent withnotifyRetryAfter, which also isn't env-configurable today.
Changes
domains/amazon/mock.go:
Mocksgained apollInterval time.Durationfield (defaulttime.Minute, via newdefaultPollIntervalconst) andWithPollInterval(d)builder, mirroringWithNotifyRetryAfter.ProcessEvents'sselectnow usesm.pollIntervalinstead of thetime.Minuteliteral.- Added a
Debuglog line on each of the two meaningful wake-up branches ("woke up: notification received" / "woke up: poll interval elapsed"), so it's now observable in practice which path is actually firing - previously both looked identical afterward.
domains/amazon/mock_test.go:
- New
TestProcessEvents_PollFallbackPicksUpRetryDueEvents. Proving the poll branch actually works without waiting 60s - or without any trigger/NOTIFY manipulation that would be unsafe to run against the shared dev DB - needed a bit of care: a direct insert intomock.shop_amazon_eventsisn't possible (FK tomock.raw_shop_events), and any insert intoraw_shop_eventsforplatform='amazon'unconditionally fires the trigger'spg_notify, so there's no clean way to insert an event that's guaranteed to never notify. Instead, the test reuses insight #2's retry mechanism: one real event is inserted (fires NOTIFY normally, dispatched once), the listener never acks it, and withnotifyRetryAfterset smaller thanpollInterval, the event becomes retry-due almost immediately - so the only thing that can cause a second dispatch, since nothing else ever notifies again for the rest of the test, is the poll timer in theselectfiring on its own. Confirms the mechanism cleanly and safely (no shared state touched beyond the test's own rows).
Verification
go build ./.../go vet ./...clean.- Manually confirmed the new log lines actually fire as expected: a small standalone program (not part of the repo, written to the scratchpad and deleted after) run against the test DB with
WithPollInterval(60ms)printed"woke up: poll interval elapsed"on a steady ~60ms cadence. go test ./domains/amazon/... -v -race: all 6 tests pass (5 existing + 1 new).- 10x repeated runs (
-count=1 -race) with no flakes, ~1.4-1.5s each. make test/make test-against-dev-db: full suite green both ways; zero leftover rows in the dev DB afterward.
Follow-ups / not done here
- Insight #4 (a LISTEN-connection error is fatal to the entire application, not just this processor - the most consequential one, given eleven more platforms already share this trigger shape in the migrations) remains open, next in line per the user's one-at-a-time request.