PR-4: an aired announcement is recorded once (STORY-469) - #836
Merged
Merged
Conversation
The aired-confirmation queue is now unbounded, so a signal is never refused. The drain retries MarkAiredAsync at 1 s, 5 s and 30 s on a TimeProvider, then logs one WARN with the id and drops it; the guardian's re-arm sweep stays the fallback. MarkAiredAsync only stamps rows whose aired_at is null, so a duplicate signal is a silent no-op. A booth-log append failure no longer undoes the aired stamp. Story469 AC1-AC7 un-skipped; the idempotency facts run against real Postgres in MediaLibrary.Tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 What
PR-4 of the launch-polish epic: STORY-469, an aired announcement is recorded once (SPEC F202). One commit ahead of
main.Fixes #773.
AnnouncementAiredEventSinkwrites to an unbounded channel (F202.1).AnnouncementAiredDrainServiceretriesMarkAiredAsyncat 1 s, 5 s and 30 s on aTimeProvider, then logs one WARN with the id and drops it; the guardian's re-arm sweep remains the fallback (F202.2).MarkAiredAsynconly stamps rowswhere aired_at is null, so a second signal returns null silently (F202.3).🔬 Wire evidence (T555, dev station on the branch image)
Announcement #4 was posted through
POST /api/announcementson a settled station. After it was claimed, the db wasdocker paused for ~3 s across each item change until the announcement was on air:aired_atannouncement-airedbooth rowsA paused container stalls the connection rather than refusing it, so this run proves the stamp survives a db stall. The fault-and-retry path itself (AC4, AC6, AC7 and the 1/5/30 s backoff) is pinned by the Story469 facts on a fake clock.
Full solution (
dotnet test GenWave.sln --filter "Category!=Integration", Host withMaxParallelThreads=3): 0 failed across all 9 projects (Host 3090 / 40 skipped, MediaLibrary 177). MediaLibrary Integration: 34/34, including the two new real-Postgres idempotency facts.WaitUntilAsync-style helpers in Story374/375/379 duplicate each other; Story469'sCountingFakeTimeProvideris a fourth shape of the same idea.