pub struct WsDispatchState {
pub order_identities: DashMap<ClientOrderId, OrderIdentity>,
pub emitted_accepted: DashSet<ClientOrderId>,
pub filled_orders: DashSet<ClientOrderId>,
pub order_symbol_cache: DashMap<String, String>,
pub order_client_id_cache: DashMap<String, ClientOrderId>,
pub delta_snapshots: DashMap<ClientOrderId, DeltaSnapshot>,
pub order_filled_qty: DashMap<ClientOrderId, Quantity>,
pub emitted_trades: Mutex<IndexSet<TradeId>>,
/* private fields */
}Expand description
Per-client dispatch state shared between order submission and the WebSocket consumer task.
Tracks which orders were submitted through this client (so we can route
venue events to typed [OrderEventAny] emissions for tracked orders, and
fall back to reports for external orders), and provides cross-stream
dedup for OrderAccepted and OrderFilled emissions.
Fields§
§order_identities: DashMap<ClientOrderId, OrderIdentity>Tracked orders keyed by full Nautilus [ClientOrderId].
emitted_accepted: DashSet<ClientOrderId>Client order IDs for which an OrderAccepted event has been emitted.
filled_orders: DashSet<ClientOrderId>Client order IDs that have reached the filled terminal state.
order_symbol_cache: DashMap<String, String>Symbol captured from execution frames for a venue order id.
Kraken’s spot v2 executions channel sends a pending_new frame with
full order details, then follow-up frames (new, amended,
restated, status) that omit fields which have not changed —
Kraken’s docs show symbol omitted on the new delta. The dispatch
needs the symbol to resolve the instrument, so we cache it here from
any frame that carries it (first writer wins). Keyed by venue
order_id because delta frames often lack cl_ord_id as well.
Known limitation: the live spot execution client currently subscribes
with snap_orders=false (see execution/spot.rs). Orders that were
already open at the venue before this process connected therefore do
not receive an in-session pending_new, and if their next delta
frame omits symbol it is dropped at symbol resolution. State for
such orders is recovered via REST reconciliation
(request_order_status_reports). Enabling snap_orders=true would
allow the executions snapshot to seed the cache for pre-existing
orders.
Steady-state eviction happens on terminal exec types
(Canceled/Filled/Expired). Bounded by DEDUP_CAPACITY as a
safety net so missed terminal frames (reconnects, partial replays)
cannot leak entries indefinitely.
order_client_id_cache: DashMap<String, ClientOrderId>ClientOrderId captured from execution frames for a venue order id.
Kraken’s pending_new echoes our submitted cl_ord_id, but follow-up
delta frames (new, amended, restated, status) routinely omit
it. Without this mapping the dispatch cannot resolve the tracked
order from a delta and falls back to the untracked report path,
which loses the typed OrderAccepted event — the symptom behind
issue #4051.
Populated whenever a frame resolves a cl_ord_id (first writer
wins, keyed by venue order_id). Consulted when exec.cl_ord_id
is None. Mirrors the venue_client_map used by the futures
dispatch path.
Eviction policy matches order_symbol_cache: cleared on terminal
exec types and bounded by DEDUP_CAPACITY as a safety net.
delta_snapshots: DashMap<ClientOrderId, DeltaSnapshot>Last snapshot of qty / filled / price / trigger_price seen on a
tracked OpenOrdersDelta.
The futures delta path uses this map to discriminate partial-fill
notifications (the new delta carries filled greater than the
previously seen value), modify acknowledgements (a non-fill field
changed), and pure no-op deltas (nothing changed). It is updated only
by the delta path so that the fill path’s own cumulative is not
double-counted.
order_filled_qty: DashMap<ClientOrderId, Quantity>Cumulative filled quantity per tracked client order id, populated by the fill side of dispatch.
Compared against OrderIdentity::quantity to decide when to clean up
tracked state on a terminal fill.
emitted_trades: Mutex<IndexSet<TradeId>>Trade IDs for which an OrderFilled event has been emitted.
Bounded FIFO dedup: when capacity is reached, the oldest entry is
evicted on the next insert. A simple clear() at the threshold would
drop all recent trade IDs at once, opening a window where a reconnect
or replay immediately after the rollover could re-emit duplicate
OrderFilled events.
Implementations§
Source§impl WsDispatchState
impl WsDispatchState
Sourcepub fn register_identity(
&self,
client_order_id: ClientOrderId,
identity: OrderIdentity,
)
pub fn register_identity( &self, client_order_id: ClientOrderId, identity: OrderIdentity, )
Registers an order identity. Called by the execution client at order submission time, before any WebSocket events for the order can arrive.
Sourcepub fn lookup_identity(
&self,
client_order_id: &ClientOrderId,
) -> Option<OrderIdentity>
pub fn lookup_identity( &self, client_order_id: &ClientOrderId, ) -> Option<OrderIdentity>
Returns a clone of the identity for the given client order id, if any.
Sourcepub fn insert_accepted(&self, cid: ClientOrderId) -> bool
pub fn insert_accepted(&self, cid: ClientOrderId) -> bool
Atomically marks an OrderAccepted event as emitted for this order.
Returns true when the entry was newly inserted (caller should emit the
event), and false when an entry was already present (caller should
skip emission). Replaces the racier “contains-then-insert” pattern,
which allowed concurrent emitters to both observe false from
contains and then both insert + emit duplicate OrderAccepted events.
Sourcepub fn insert_filled(&self, cid: ClientOrderId)
pub fn insert_filled(&self, cid: ClientOrderId)
Marks an order as having reached the filled terminal state.
Sourcepub fn cache_order_symbol(&self, order_id: &str, symbol: &str)
pub fn cache_order_symbol(&self, order_id: &str, symbol: &str)
Caches the symbol for a venue order_id if not already present.
Atomic via [DashMap::entry] so concurrent callers cannot overwrite an
existing cached value — first writer wins, all later writers no-op.
The cheap contains_key fast path skips the key allocation when the
entry already exists; the or_insert_with covers the race that opens
between that check and the insert.
Sourcepub fn lookup_order_symbol(&self, order_id: &str) -> Option<String>
pub fn lookup_order_symbol(&self, order_id: &str) -> Option<String>
Returns the symbol previously cached for a venue order_id, if any.
Sourcepub fn forget_order_symbol(&self, order_id: &str)
pub fn forget_order_symbol(&self, order_id: &str)
Removes any cached symbol for a venue order_id. Called when the order
reaches a terminal state on the executions stream.
Sourcepub fn cache_order_client_id(
&self,
order_id: &str,
client_order_id: ClientOrderId,
)
pub fn cache_order_client_id( &self, order_id: &str, client_order_id: ClientOrderId, )
Caches the resolved ClientOrderId for a venue order_id if not
already present.
Atomic via [DashMap::entry] so concurrent callers cannot overwrite an
existing cached value — first writer wins. The cheap contains_key
fast path skips the key allocation when the entry already exists.
Sourcepub fn lookup_order_client_id(&self, order_id: &str) -> Option<ClientOrderId>
pub fn lookup_order_client_id(&self, order_id: &str) -> Option<ClientOrderId>
Returns the ClientOrderId previously cached for a venue order_id,
if any.
Sourcepub fn forget_order_client_id(&self, order_id: &str)
pub fn forget_order_client_id(&self, order_id: &str)
Removes any cached ClientOrderId for a venue order_id. Called when
the order reaches a terminal state on the executions stream.
Sourcepub fn check_and_insert_trade(&self, trade_id: TradeId) -> bool
pub fn check_and_insert_trade(&self, trade_id: TradeId) -> bool
Atomically inserts a trade id into the dedup set.
Returns true when the trade was already present (i.e. it is a
duplicate), false otherwise. When the dedup set is at capacity the
oldest entry is evicted to make room, preserving the DEDUP_CAPACITY
most recently seen trade IDs.
Sourcepub fn cleanup_terminal(&self, client_order_id: &ClientOrderId)
pub fn cleanup_terminal(&self, client_order_id: &ClientOrderId)
Removes all dispatch state for an order that has reached a terminal state.
Sourcepub fn record_filled_qty(&self, client_order_id: ClientOrderId, qty: Quantity)
pub fn record_filled_qty(&self, client_order_id: ClientOrderId, qty: Quantity)
Records cumulative filled quantity for a tracked order. Used by the fill side of dispatch only.
Sourcepub fn previous_filled_qty(
&self,
client_order_id: &ClientOrderId,
) -> Option<Quantity>
pub fn previous_filled_qty( &self, client_order_id: &ClientOrderId, ) -> Option<Quantity>
Returns the previously recorded cumulative filled quantity, if any.
Sourcepub fn record_delta_snapshot(
&self,
client_order_id: ClientOrderId,
snapshot: DeltaSnapshot,
)
pub fn record_delta_snapshot( &self, client_order_id: ClientOrderId, snapshot: DeltaSnapshot, )
Records the latest delta snapshot for a tracked order. Used by the delta side of dispatch only.
Sourcepub fn previous_delta_snapshot(
&self,
client_order_id: &ClientOrderId,
) -> Option<DeltaSnapshot>
pub fn previous_delta_snapshot( &self, client_order_id: &ClientOrderId, ) -> Option<DeltaSnapshot>
Returns the previously recorded delta snapshot, if any.
Sourcepub fn update_identity_quantity(
&self,
client_order_id: &ClientOrderId,
quantity: Quantity,
)
pub fn update_identity_quantity( &self, client_order_id: &ClientOrderId, quantity: Quantity, )
Updates the tracked quantity for an order following a successful
modify acknowledgement, leaving all other identity fields untouched.
Trait Implementations§
Source§impl Debug for WsDispatchState
impl Debug for WsDispatchState
Auto Trait Implementations§
impl !Freeze for WsDispatchState
impl !RefUnwindSafe for WsDispatchState
impl Send for WsDispatchState
impl Sync for WsDispatchState
impl Unpin for WsDispatchState
impl UnsafeUnpin for WsDispatchState
impl UnwindSafe for WsDispatchState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more