Skip to content

Assign per-project atomic sequence numbers when recording events - #33

Merged
johardi merged 1 commit into
epic/303-ssefrom
feat/296-shared-sequence
Jul 27, 2026
Merged

Assign per-project atomic sequence numbers when recording events#33
johardi merged 1 commit into
epic/303-ssefrom
feat/296-shared-sequence

Conversation

@johardi

@johardi johardi commented Jul 25, 2026

Copy link
Copy Markdown
Member

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 (channel webprotege.events.projects.SequencedPackagedProjectChange; fields projectId, 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).

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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant