feat(ws): add fail-closed ordered market stream and shutdown - #110
feat(ws): add fail-closed ordered market stream and shutdown#110yovanoc wants to merge 8 commits into
Conversation
|
Downstream PMKit dogfood found and exercised three lifecycle needs now included in follow-up commits:
The complete PMKit runtime integration now reconstructs token-scoped snapshot+deltas from this stream and passes 438 workspace tests, including GTD execution regressions against SDK 0.7. SDK validation remains 163 library + 47 WebSocket tests and strict lib clippy. |
|
Full PMKit dogfood completed using #110 plus #105 on fork integration branch |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
Reviewed by Cursor Bugbot for commit 109abdd. Configure here.
|
Addressed both Cursor findings in |

Closes #109.
Motivation
Consumers maintaining a local executable orderbook need the initial
BookUpdate, every batchedPriceChange, and related market events in one connection-ordered stream. Merging the existing typed streams can miss/reorder the initial snapshot and deltas; lag and malformed interested frames previously disappeared without a terminal error. Downstream runtimes also had no way to await WebSocket/reconnection shutdown.Changes
Client::subscribe_market_eventsand_with_options, returning one orderedStream<Item = Result<WsMessage>>;WsError::Lagged;ConnectionEventstream while preserving the existing publicConnectionManager::subscribe() -> Receiver<M>API;Side::Unknownremain visible to callers;Client::shutdown()/close()that blocks new channel creation during shutdown, stops and awaits reconnect/connection tasks, and permits clean later reuse;Unsubscribe remains transport/refcount management; callers should drop a returned stream when they no longer want to consume it. Channels stay alive to flush unsubscribe messages and support reuse until explicit shutdown or final Client drop.
Tests
Validation:
cargo test --all-features --no-fail-fast— 611 passed, 20 ignoredcargo test --all-features --test websocket— 45 passedcargo clippy --all-features --lib -- -D warningscargo clippy --all-features --test websocket -- -D warningscargo check --all-features --workspace --all-targets(two pre-existing unused imports in unrelated order tests)Note
Medium Risk
Touches core WebSocket subscription, reconnect, and shutdown paths; behavior changes (lag/parse fail-closed, channel retention, all-markets user semantics) can affect long-running orderbook consumers.
Overview
Adds
subscribe_market_events(and_with_options) so book snapshots, price deltas, and related market frames share one connection-orderedStream<Item = Result<WsMessage>>, plusunsubscribe_market_eventsandClient::isolated()for independent channel lifecycles.Lifecycle and transport:
shutdown/shutdown_if_idle/closeare idempotent and coordinate with a lifecycle lock so idle shutdown cannot race subscription setup; channels are no longer torn down automatically when refcounts hit zero (unsubscribe flush and reuse until explicit shutdown).ConnectionManagergains cancellable shutdown, a larger broadcast buffer, and an internalConnectionEventpath (messages, parse errors, shutdown) while keeping the publicsubscribe()API.Fail-closed streaming: Subscriptions register receivers before wire requests; setup failures roll back refcounts/interest/auth. Broadcast lag and parse errors end the stream with
WsError::Lagged/InvalidMessageinstead of continuing silently. Interested batch parse failures inparse_if_interestedpropagate rather than being skipped. RTDS picks up the same event stream behavior and ignores control acks without topic/type/payload.User channel: Empty
markets(“all markets”) subscriptions are refcounted separately so targeted unsubscribes and reconnect resubscribe do not break the global stream.Reviewed by Cursor Bugbot for commit 39a3fe3. Bugbot is set up for automated code reviews on this repo. Configure here.