WIP: feat(realtime): print on several application nodes (shared wakeups, durable connection record, claim gate on any node) #36

Draft
james.maes wants to merge 2 commits from feat/multi-node-realtime-20261110 into main
pull from: feat/multi-node-realtime-20261110
2 Commits
Author SHA1 Message Date
james.maesandClaude Fable 5.2 42dff1ff39 docs(realtime): describe printing on several application nodes
maven / build (push) Successful in 4m20s
build / maven (push) Successful in 4m20s
REALTIME.md replaces the single-node boundary with what is shared and where
(jobs and the claim, the connection record, the claim gate, wakeups), what
happens when the shared bus loses a wakeup, the delivery guarantee, the four
columns a host that owns its schema must add, and what is and is not verified.
README, OPERATIONS and the changelog follow.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 16:47:33 -06:00
james.maesandClaude Fable 5.2 4aa63ae1d1 feat(realtime): print on several nodes: shared wakeups, a durable connection record and a claim gate any node can answer
maven / build (push) Successful in 3m37s
build / maven (push) Successful in 3m37s
A device holds one realtime connection, on one node. Until now the wakeup
listeners, the connection ownership and the claim gate lived in that JVM, so a
job accepted on another node never reached the device, and a claim that
reached another node was refused with 409.

- PrintingRealtimeBus joins the application's QQQ realtime bus (in memory on
  one node, the configured shared bus such as Redis on several). A wakeup is
  delivered to this JVM directly and handed to the shared bus by a bounded
  background worker, so the committing caller never waits for the transport.
  The route provider joins at start; hosts need no new wiring.
- The connection is recorded on the device row (connection id, node, ready
  flag, lease). Every statement is a guarded update: the newest connection
  takes the row, only the named connection can renew, mark or clear it. The
  claim gate accepts a claim on a node without the socket when the row shows
  a live, ready connection and the device has applied the current desired
  state and settings.
- On every heartbeat (PING) the connection renews its lease and asks the
  database whether anything was committed that it has not been told; a
  wakeup the bus lost costs at most one heartbeat interval. A connection
  replaced through another node closes on the bus message, or on its next
  frame when the bus is down.
- The QUEUED to CLAIMED update carries a status guard in addition to the
  device row lock.
- A database failure during the socket upgrade answers 503 (retryable), not
  403, which a client treats as "ask a person to sign in".

Tests: two services with separate buses and route providers over one database
and one application bus (wake, claim over HTTP on the other node, events on
either node, bus down, replacement), the bus on its own, and the claim,
acknowledgement and connection record on PostgreSQL 17 (Testcontainers).

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 16:39:22 -06:00