Fix #91: atomic unread dedup #100
No reviewers
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub!100
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/issue-91"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #91.
Unread-dedup check-then-act race in internal/notify/emit.go: createOne checked hasUnread then Created with a seq-embedded id, so concurrent same-(user,thread,reason) emissions minted duplicate tray rows (different ids defeat the index CAS).
Fix (entry-level discipline, no new locks): the triple is re-checked INSIDE the unread-index CAS loop (new indexClaim over shared indexUpsert body; indexAdd keeps id-only semantics). hasUnread stays as a fast path. A CAS loser best-effort deletes its just-Created orphan object and reports createSkipped, converging tray and bucket to one row + one object. notify-fanout backfill (fanoutOne, same race shape) now delegates to createOne instead of duplicating the sequence. §4 Create->index->activity->stream order unchanged.
Tests: new TestEmitConcurrentSameTripleDedups (16 goroutines, start barrier, no sleeps) asserts 1 created / 15 skipped, one unread index row with count 1, one notification object. Fails pre-fix (14 created), green post-fix -race -count=20. Package coverage 97.3% (>=95%). gofmt/vet clean.
Docs: Decisions entry in docs/features/06_notifications.md (law 12).