Skip to content

feat(trade): pool TradeContext connections instead of opening one per call - #135

Open
hogan-yuan wants to merge 1 commit into
mainfrom
feat/trade-context-pooling
Open

feat(trade): pool TradeContext connections instead of opening one per call#135
hogan-yuan wants to merge 1 commit into
mainfrom
feat/trade-context-pooling

Conversation

@hogan-yuan

Copy link
Copy Markdown
Member

Summary

Split out of #134, which bundled this with unrelated fixes.

Every trade tool call (15 call sites across trade.rs and portfolio.rs) opened a fresh WebSocket connection via TradeContext::new(), unlike QuoteContext which has always been pooled per identity via ws_pool.rs. Under concurrent load this plausibly contributes to elevated error rates on trade-related tools (connection-limit/timeout errors), and is architecturally inconsistent with how quote calls are handled.

  • Extracted the pooling engine (LRU + idle-TTL + per-key init serialization + eviction-on-error) out of ws_pool.rs into a generic context_pool.rs.
  • Added trade_pool.rs as a TradeContext pool built on it, mirroring ws_pool.rs exactly (same identity-keying, own Prometheus metrics, own env vars for tuning).
  • Rewired all 15 TradeContext::new() call sites through mctx.get_trade_context(), with eviction-on-error wired into every trade error path.
  • Added a compile-time lint (trade_tools_use_pooled_context_constructor) mirroring the existing quote-side one, so any future trade tool that bypasses the pool fails CI.

Test plan

  • cargo build clean
  • cargo +nightly fmt --check clean
  • cargo clippy --all-features --all-targets -- -D warnings clean
  • cargo test — 207 passed, 0 failed
  • Both #[ignore]d stress tests (stress_pool_bounded_concurrency, stress_high_concurrency) run manually against real thread contention and pass

… call

Every trade tool call (15 call sites across trade.rs and portfolio.rs)
opened a fresh WebSocket connection via TradeContext::new(), unlike
QuoteContext which has always been pooled per identity via ws_pool.rs.
Under concurrent load this plausibly contributes to elevated error
rates on trade-related tools (connection-limit/timeout errors), and is
architecturally inconsistent with how quote calls are handled.

Extracted the pooling engine (LRU + idle-TTL + per-key init
serialization + eviction-on-error) out of ws_pool.rs into a generic
context_pool.rs, and added trade_pool.rs as a TradeContext pool built
on it, mirroring ws_pool.rs exactly (same identity-keying, own
Prometheus metrics, own env vars for tuning). Rewired all 15
TradeContext::new() call sites through mctx.get_trade_context(), with
eviction-on-error wired into every trade error path so a broken pooled
connection doesn't get reused. Added a compile-time lint
(trade_tools_use_pooled_context_constructor) mirroring the existing
quote-side one, so any future trade tool that bypasses the pool fails
CI.

Split out from PR #134 (which bundled this with unrelated fixes) to
keep it independently reviewable.
hogan-yuan added a commit that referenced this pull request Aug 31, 2026
Splits out everything pooling-related from this PR to keep it
independently reviewable: reverts src/tools/trade.rs, src/tools/portfolio.rs,
src/main.rs, src/metrics.rs, and src/ws_pool.rs to their pre-pooling
state, removes src/context_pool.rs and src/trade_pool.rs, and drops
McpContext::get_trade_context()/evict_trade_context() plus the
trade-pooling compile-time lint from src/tools/mod.rs.

The pooling work itself now lives on feat/trade-context-pooling (#135),
unchanged from what was here. This PR is left with: the option_quote
symbol-format documentation fix, the candlesticks count validation/
boundary-retry fix, the error_hint structured-error-code improvements,
and the version bump.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant