Skip to main content

brokapi_runtime/
lib.rs

1//! Connector runtime: the building blocks every broker connector shares.
2//!
3//! This is the layer between the broker-specific protocol code and the capability traits of
4//! [`brokapi_core`]. It holds the parts that do not depend on a broker and do no network I/O, so
5//! they are the same for BCS, T-Bank and Finam and can be tested with plain values.
6//!
7//! | Need | Type |
8//! |---|---|
9//! | Stay under the broker's rate limits | [`BrokerLimiter`], [`BrokerLimits`], [`BucketCfg`], [`ConnQuota`] |
10//! | Refuse trading before the first reconcile, after an overflow, during shutdown | [`CommandGate`] |
11//! | Compare the client's order ledger with the broker | [`reconcile_ledger`] |
12//! | Send events to the consumer without blocking, with a loss policy per subscription | [`Emitter`], [`BackpressureManager`], [`SubscriptionBuffer`], [`PushResult`] |
13//! | Hold `subscribe_*` until the broker has confirmed the stream | [`wait_ack`], [`AckState`] |
14//! | Never send the same place twice, track unanswered orders | [`OrderRuntime`] |
15//! | Finish a command even when the caller stops waiting | [`run_detached`] |
16//! | One command at a time per instrument, in order | [`InstrumentLocks`] |
17//! | Refuse an order price off the price step before sending | [`PriceGrid`] |
18//! | Decide when to resubscribe or reconnect | [`Supervisor`], [`ConnectionState`], [`ConnectionHealth`] |
19//! | Stop cleanly | [`ShutdownController`] |
20//! | Read a long candle history within the broker's span and rate limits | [`history::CandlePages`], [`history::load_candles`] |
21//! | Record the event stream to a file and play it back | [`record::EnvelopeWriter`], [`record::EnvelopeReader`], [`record::replay`] |
22//!
23//! Limits belong to the broker user, not to a connector: build one [`BrokerLimiter`] per user and
24//! share its [`Arc`](std::sync::Arc) between all connectors of that user.
25//!
26//! The book is at <https://brokapi.ru/docs/>.
27//!
28//! # Examples
29//!
30//! A trading command passes two checks before it is sent: the command gate and the rate limiter.
31//!
32//! ```
33//! use std::time::Instant;
34//! use brokapi_core::Error;
35//! use brokapi_runtime::{BrokerLimiter, BrokerLimits, CommandGate};
36//!
37//! # let raw = r#"
38//! # [demo.buckets.orders]
39//! # rate = 10
40//! # per = "1s"
41//! # burst = 1
42//! # [demo.route]
43//! # PlaceOrder = ["orders"]
44//! # [demo.conns]
45//! # max_conns = 2
46//! # max_subs_per_conn = 50
47//! # supports_multiplex = false
48//! # "#;
49//! let limiter = BrokerLimiter::new(&BrokerLimits::from_toml_str(raw)?);
50//! let mut gate = CommandGate::new();
51//!
52//! // Before the first reconcile no command may go out.
53//! assert!(matches!(gate.check_command(), Err(Error::NotReconciled)));
54//! gate.mark_reconciled();
55//!
56//! // Now the gate is open and the limiter lets the first order through. The second one, sent
57//! // at once, is refused locally. Nothing reached the broker.
58//! let now = Instant::now();
59//! assert!(gate.check_command().is_ok());
60//! assert!(limiter.acquire("PlaceOrder", now).is_ok());
61//! assert!(matches!(limiter.acquire("PlaceOrder", now), Err(Error::RateLimited { .. })));
62//! # Ok::<(), brokapi_core::ConfigError>(())
63//! ```
64
65#![warn(missing_docs)]
66
67mod ack;
68mod backpressure;
69mod clock;
70mod command_gate;
71mod connection;
72mod detached;
73mod emitter;
74mod health;
75pub mod history;
76mod instrument_queue;
77mod limits;
78mod metrics;
79mod orders;
80mod price_grid;
81mod reconcile;
82pub mod record;
83mod shutdown;
84mod supervisor;
85
86pub use ack::{AckState, SUBSCRIPTION_REFUSED, not_confirmed, wait_ack};
87pub use backpressure::{BackpressureManager, PushResult, SubscriptionBuffer};
88pub use clock::now;
89pub use command_gate::CommandGate;
90pub use connection::{ConnectionState, SubState};
91pub use detached::run_detached;
92pub use emitter::Emitter;
93pub use health::{ConnectionHealth, HealthClass};
94pub use instrument_queue::{BOUND_CIDS, InstrumentGuard, InstrumentLocks};
95pub use limits::{
96    BrokerLimiter, BrokerLimits, BucketCfg, BucketId, ConnQuota, DEFAULT_ROUTE, MethodId,
97};
98pub use metrics::RuntimeMetrics;
99pub use orders::{FinishedWindow, OrderRuntime, RETAINED_FINISHED, RETENTION};
100pub use price_grid::PriceGrid;
101pub use reconcile::reconcile_ledger;
102pub use shutdown::ShutdownController;
103pub use supervisor::{ReconcileAction, Supervisor};