Repository navigation
feat(ws)!: late-join snapshots from the record's current value (#434) - #439
Merged
Merged
Conversation
WebSocket kept a per-(record, topic) cache of the last bytes it sent and served late-join snapshots from it. Snapshots now come from the record's current value, rendered through the link's topic writer and serializer when a client subscribes, as AimX does. - aimdb-core: new `OutboundLatest`, each outbound link's current value rendered on demand, with the same route ids as `OutboundRoutes`. Each `ConnectorLink` carries the renderer next to its route factory. - aimdb-websocket-connector: the snapshot cache, `SnapshotProvider`, `NoSnapshot` and `server/session.rs` are gone; `run_broadcast` only fans out. Behaviour changes: `SpmcRing` records send no snapshot, and a record with a topic writer sends one only on its current topic. Co-Authored-By: Claude Opus 5.5 <[email protected]>
`OutboundLatest::render_if(id, accept)` runs the link's topic writer, checks the topic with `accept`, and serializes only on a match. A link with a fixed topic is checked before its value is read. Replaces the separate `fixed_topic` pre-filter, so a WebSocket subscribe never serializes links its pattern does not match. Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.
Closes #434. Related to #422 and #438.
Problem
AimX builds late-join snapshots from each record's current value when a client subscribes. WebSocket instead cached the last bytes it sent per
(record, topic)in aMutex<HashMap>on the broadcast path and served snapshots from that. It was a second copy of state the database already holds. With a topic writer, it gained one entry for every distinct topic ever published and never shrank. And it gave WebSocket and AimX clients different initial state.Change
aimdb-coreOutboundLatest(outbound/latest.rs), built per scheme likeOutboundRoutesand using the same route ids.render(id)reads the record's current value (TypedRecord::latest, i.e. bufferpeek) and runs it through the link's topic writer and serializer, returningLatestMessage { record_index, topic, payload, metadata }. It keeps no state and needs nowith_remote_access().render_if(id, accept)resolves the topic first and serializes only ifaccepttakes it; a link with a fixed topic is checked before its value is even read.ConnectorLinkcarries the renderer (latest_fn) next to its route factory, built intyped_api.rsfrom the same serializer and topic writer the live route uses.aimdb-websocket-connectorWsSession::snapshotscallsrender_ifwith the subscribe pattern for each route the client may read, so non-matching links are never serialized.SnapshotCache,DynMapSnapshot), the crate-privateSnapshotProvider/NoSnapshot/Snapshot, andserver/session.rs.run_broadcastonly fans out.with_late_joindocs describe the new behaviour.Tests (
tests/e2e.rs)SingleLatestrecords (sensors.temp,sensors.humidity,t) and aSingleLatestrecord with a topic writer (moving). The existing snapshot and golden-frame tests use them and no longer needsleep(100ms), since snapshots read the record directly.ring_records_send_no_snapshot: a ring record's subscriber gets the next live event first, with nosnap.topic_writer_snapshot_is_on_the_current_topic: after writing onm.athenm.b,m.#gets one snapshot, onm.b.snapshots_serialize_only_matching_links: a counting serializer shows a non-matching subscribe serializes nothing and a matching one serializes once.decouple_record_keys_topics.rs, including the permission-filtered one, pass unchanged.CHANGELOG entries for
aimdb-core(Added) andaimdb-websocket-connector(Changed, breaking, wire).Behaviour changes
SpmcRingrecords send no snapshot, as on AimX. A ring has no current value. Records whose subscribers need the current value should useSingleLatest.Not changed
aimdb-weather-mesh's hub uses rings, but only withlink_from, not WebSocketlink_to, so it is unaffected.Merging alongside #437
#437 touches
record_queryinserver/dispatch.rsand theaimdb-coreCHANGELOG. A trial merge of both branches applied cleanly.Tested locally
cargo test -p aimdb-websocket-connector --all-features(e2e run 3×)cargo test -p aimdb-corewith the Makefile's four feature sets (alloc,std,tracing,std,tracing,observability,alloc,observability)cargo clippy -p aimdb-core -p aimdb-websocket-connector -p aimdb-mqtt-connector --all-targets --all-features -- -D warningscargo clippy -p embedded-check-fixture --target thumbv7em-none-eabihf -- -D warningscargo doc -p aimdb-core -p aimdb-websocket-connector --no-deps --all-featurescargo fmt --checkThe full suite runs in CI.
🤖 Generated with Claude Code