Skip to content

Journal: event streams share one watcher per process instead of each polling - #105

Merged
PALBIBEK merged 1 commit into
mainfrom
journal-watch
Nov 3, 2026
Merged

PALBIBEK merged 1 commit into
mainfrom
journal-watch

Conversation

@PALBIBEK

@PALBIBEK PALBIBEK commented Nov 3, 2026

Copy link
Copy Markdown
Owner

Every open stream read the journal and the partial reply four times a second and its
session's status every two: 500 streams took the API's p95 to 2.5 s.
supervisor.journal.watch asks once a round for every session the process's streams
follow (last seq, status, partial reply time; one query per 500 sessions) and wakes
the streams whose session changed. On Postgres each journal write and partial reply
notifies on commit (pg_notify) and the watch listens, so a stream wakes as soon as the
write lands; the shared poll then runs every 2 s as a backstop, and a dropped listening
connection is noticed there and reopened, polling fast meanwhile.

A watched stream reads only when its session changed and ends when its status closes
(or the session is gone). Without a watch, iter_journal_sse polls as before.

Journal plan, PR 7 of 12. Stacked on journal-indexes; this PR's own change is its last commit.

Tests

  • New and changed tests pass on SQLite and Postgres (SUPERVISOR_TEST_PG_URL); ruff and mypy are clean.
  • The full supervisor suite passes locally (1606 passed), and CI is green on the stack's tip (journal-cleanup): lint and types, tests, backend, frontend, e2e, compose smoke, journeys.

Generated by Claude Code

@PALBIBEK
PALBIBEK changed the base branch from journal-indexes to main November 3, 2026 21:42
…polling

Every open stream read the journal and the partial reply four times a second and its
session's status every two: 500 streams took the API's p95 to 2.5 s.
supervisor.journal.watch asks once a round for every session the process's streams
follow (last seq, status, partial reply time; one query per 500 sessions) and wakes
the streams whose session changed. On Postgres each journal write and partial reply
notifies on commit (pg_notify) and the watch listens, so a stream wakes as soon as the
write lands; the shared poll then runs every 2 s as a backstop, and a dropped listening
connection is noticed there and reopened, polling fast meanwhile.

A watched stream reads only when its session changed and ends when its status closes
(or the session is gone). Without a watch, iter_journal_sse polls as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ge2HHQ32aPUxZf3EnfAfpt
@PALBIBEK
PALBIBEK merged commit 58afa42 into main Nov 3, 2026
1 of 7 checks passed
PALBIBEK added a commit that referenced this pull request Nov 4, 2026
…abase notifications (#114)

#105 sent pg_notify with every journal write and partial reply. A transaction that
sends one takes a lock on the whole Postgres server as it commits, so every commit on
the server waited its turn (16 writers: 348 appends/s with notifications, 394
without; worse as writers grow), and behind a pooler in transaction mode the
listening connection would silently hear nothing. Writes no longer notify, and the
watch has no listening connection: its shared poll runs every 150 ms (one small
query per process, whatever the number of streams), a starting stream is told at
once, and a session's end is seen within a round instead of within 2 s. The journal
package's docstring now says what each module is.


Claude-Session: https://claude.ai/code/session_01Ge2HHQ32aPUxZf3EnfAfpt

Co-authored-by: Claude <noreply@anthropic.com>
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.

2 participants