Skip to content

Push the real per-project sequence number instead of hardcoded event tags - #47

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

Push the real per-project sequence number instead of hardcoded event tags#47
johardi merged 2 commits into
epic/303-ssefrom
feat/296-shared-sequence

Conversation

@johardi

@johardi johardi commented Jul 25, 2026

Copy link
Copy Markdown
Member

The gateway half of protegeproject/webprotege-gwt-ui#296 (part of protegeproject/webprotege-gwt-ui#303). Stacked on #46; retarget to epic/303-sse once that merges. Producer side: protegeproject/webprotege-event-history-service#33.

Every pushed window carried hardcoded tags 0→1, so the client's stale-window guard dropped every push after the first — the socket went silent and delivery fell back to the 10s poll (the direct cause of the ~9.5s median UI latency in the epic's baseline). The emitter now consumes the post-persistence SequencedPackagedProjectChangeEvent and pushes truthful tags (startTag = seq-1, endTag = seq). Wire payload shape unchanged — the client deserializes exactly as before (pinned by a JSON field-name test, since there is no shared DTO artifact). Also includes the exception in the error log (previously dropped).

Tests: 4/4 (handler test migrated to JUnit 5 so it actually executes — this repo skips JUnit 4 silently).

johardi added 2 commits July 24, 2026 20:56
Viewers can now open GET /data/projects/{projectId}/events as a
server-sent-events stream. A registry keeps the open streams per project
and fans incoming payloads out on an executor, evicting dead emitters on
send failure; a scheduled comment heartbeat keeps idle streams alive
through nginx's 60-second proxy read timeout, and the path rides the
existing /data/ route so no proxy changes are needed (response buffering
is disabled per-response with X-Accel-Buffering).

Authorization at stream-open mirrors the STOMP subscribe check: the
caller must hold ViewProject on the project, with identity resolution
isolated in one seam that #305 replaces with a short-lived redeemable
ticket. The Last-Event-ID header (and a lastEventId query fallback for
fresh loads, which never send the header) is plumbed to a catch-up seam
whose real replay implementation arrives with the sequence work; streams
also get a finite lifetime so every reconnect re-authorizes.

Nothing publishes into the registry yet — the broker bridge lands
separately once events carry real sequence numbers (#296).

Part of protegeproject/webprotege-gwt-ui#304
(epic protegeproject/webprotege-gwt-ui#303).
…tags

Every pushed event window carried the hardcoded tags 0 to 1, so after the
first window advanced a client's bookmark past 1, the client's stale-
window guard dropped every subsequent push — the websocket went silent
after one event and delivery quietly fell back to the 10-second poll.
That is the direct cause of the ~9.5s median UI latency measured in the
epic's baseline.

The emitter now consumes the sequenced event that the event-history
service publishes after archiving a change bundle, and pushes it with
truthful tags: startTag is the previous ordinal, endTag is the bundle's
ordinal. Because that event is emitted strictly after persistence,
anything pushed is already fetchable through the pull path. The wire
payload shape is unchanged, so the client deserializes it exactly as
before. The error log now includes the exception so failures are
diagnosable.

The gateway half of protegeproject/webprotege-gwt-ui#296
(part of protegeproject/webprotege-gwt-ui#303).
@johardi
johardi changed the base branch from feat/304-sse-endpoint to epic/303-sse July 27, 2026 19:19
@johardi
johardi merged commit d1c0d16 into epic/303-sse Jul 27, 2026
1 check passed
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