Skip to main content

WsDispatchState

Struct WsDispatchState 

Source
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

Source

pub fn new() -> Self

Creates a new empty dispatch state.

Source

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.

Source

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.

Source

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.

Source

pub fn insert_filled(&self, cid: ClientOrderId)

Marks an order as having reached the filled terminal state.

Source

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.

Source

pub fn lookup_order_symbol(&self, order_id: &str) -> Option<String>

Returns the symbol previously cached for a venue order_id, if any.

Source

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.

Source

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.

Source

pub fn lookup_order_client_id(&self, order_id: &str) -> Option<ClientOrderId>

Returns the ClientOrderId previously cached for a venue order_id, if any.

Source

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.

Source

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.

Source

pub fn cleanup_terminal(&self, client_order_id: &ClientOrderId)

Removes all dispatch state for an order that has reached a terminal state.

Source

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.

Source

pub fn previous_filled_qty( &self, client_order_id: &ClientOrderId, ) -> Option<Quantity>

Returns the previously recorded cumulative filled quantity, if any.

Source

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.

Source

pub fn previous_delta_snapshot( &self, client_order_id: &ClientOrderId, ) -> Option<DeltaSnapshot>

Returns the previously recorded delta snapshot, if any.

Source

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

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for WsDispatchState

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Ungil for T
where T: Send,

§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more