Assign per-project atomic sequence numbers when recording events - #33
Merged
Conversation
This was referenced Jul 25, 2026
The archive numbered events from a single global counter incremented with a read-then-write under a JVM-local lock: not per project, and not safe with more than one service instance. Each project now has its own counter document advanced with a single findAndModify $inc, which MongoDB runs atomically server-side, so ordinals stay dense and gapless per project under concurrency. A startup migration seeds each project's counter to the maximum ordinal already archived, using setOnInsert so it is idempotent and never rewinds a counter that has advanced — newly minted numbers always stay above any bookmark a connected client still holds. After the archive write, the service now re-publishes the change bundle as a SequencedPackagedProjectChangeEvent carrying the assigned ordinal. The gateway will push that instead of the raw event, which is what lets it stamp truthful event tags — and because publication happens strictly after persistence, anything a client hears about is already fetchable through the pull path. Delivery hardening of this publish is #299's scope; the failure is not silently swallowed here. A compound index on (projectId, timeStamp) backs the pull query, and a read-only current-sequence accessor is exposed for the project-open anchor (#301). Fixes the service half of protegeproject/webprotege-gwt-ui#296 (part of protegeproject/webprotege-gwt-ui#303).
johardi
force-pushed
the
feat/296-shared-sequence
branch
from
July 27, 2026 19:22
bccdc47 to
4df7459
Compare
This was referenced Jul 27, 2026
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
The service half of protegeproject/webprotege-gwt-ui#296 (part of protegeproject/webprotege-gwt-ui#303).
The archive numbered events from one global counter behind a JVM-local lock — not per project, not multi-instance-safe. Each project now gets its own counter advanced by an atomic
findAndModify $inc; ordinals are dense and gapless per project under concurrency (verified with a concurrent-increment integration test). An idempotent startup migration seeds each counter to the project's archived maximum so new numbers stay above any bookmark a connected client holds.After the archive write the service re-publishes the bundle as
SequencedPackagedProjectChangeEvent(channelwebprotege.events.projects.SequencedPackagedProjectChange; fieldsprojectId,eventId,sequenceNumber,projectEvents) — the wire contract the gateway consumes to stamp truthful event tags (startTag = seq-1, endTag = seq) and, later, SSE ids. Publication strictly after persistence means anything pushed is already fetchable via the pull path.Also adds a compound index on
(projectId, timeStamp)for the pull query and a read-only current-sequence accessor for the project-open anchor (#301). Tests: 14/14 green under JDK 17 (Testcontainers Mongo + Rabbit).