open-standards/eoc/eoc-rs/crates/eoc-distributed/tests/kv_cache_routing.rs
Transaction Science 6ea90afbed ingest wave A4: 3 crates · smart-byte-atproto + op-openbanking + eoc-distributed
Smart Byte (1 crate, 2127 LOC, 35 tests)
  smart-byte-atproto    ATProto (Bluesky federation) adapter.
                        PLC + did:web resolution; XRPC client; CARv1 encode/decode
                        with CIDv1 (dag-cbor + raw, SHA-256); sketch MST with
                        order-independent BLAKE3 root; Repo + UnsignedCommit /
                        SignedCommit (Ed25519 over CBOR); firehose transport
                        trait + in-memory impl; AT URI ↔ smart-byte AID bridge
                        with SAID commitment.

OpenPay (1 crate, 2397 LOC, 44 tests)
  op-openbanking        UK OBIE R/W v3.1.10/3.1.11, Berlin Group NextGenPSD2
                        XS2A v1.3.13, STET PSD2 v1.7, Australia CDR Banking v1.31,
                        FDX v5/v6, SGFinDex shapes. AISP / PISP / PIIS / VRP
                        traits. FAPI 1.0 Advanced (PS256/ES256, mTLS, RFC 8705
                        certificate binding, JWK registration). Operators wire
                        their own JWS signer + HTTP transport — keeps the crate
                        KMS-agnostic.

EOC (1 crate, 2179 LOC, 32 tests)
  eoc-distributed       Distributed-inference scheduling. Worker trait with
                        Capability + Accelerator (CPU/GPU/TPU/NPU/Mixed) +
                        Load.busyness()/projected_micro_joules()/projected_g_co2e().
                        RoundRobin / LeastBusy / LatencyWeighted / JouleWeighted
                        (default) / CarbonWeighted routers. Work-stealing
                        scheduler. vLLM-style continuous batching with KV-block
                        budget. Ray-Serve-style auto-scaler with cooldown.
                        KV-cache-aware sticky-session routing.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-24 12:22:09 -04:00

122 lines
3.1 KiB
Rust

//! KV-cache-aware router keeps a session pinned to its previous worker.
use eoc_distributed::{
Accelerator, Capability, InMemoryWorker, KvCacheAwareRouter, Load, LocalRequest, Strategy,
Worker,
};
fn mk(id: &str, micro_j: u32) -> InMemoryWorker {
InMemoryWorker::new(
id,
Capability {
models: vec!["llama-70b".into()],
accelerator: Accelerator::Gpu,
max_concurrency: 16,
continuous_batching: true,
paged_kv: true,
zone: "EU-FR".into(),
},
Load {
micro_joules_per_token: micro_j,
..Load::idle()
},
)
}
#[test]
fn second_turn_pins_to_same_worker() {
let mut r = KvCacheAwareRouter::new(Strategy::JouleWeighted);
let a = mk("a", 200);
let b = mk("b", 50); // joule-cheaper
let pool: Vec<&dyn Worker> = vec![&a, &b];
let first = r
.pick(
&pool,
&LocalRequest {
session_id: "user-42".into(),
model: "llama-70b",
expected_tokens: 64,
},
)
.expect("ok")
.id()
.to_string();
// First turn — fallback picks cheapest.
assert_eq!(first, "b");
// Add a brand-new ultra-cheap worker. The locality binding must
// override the joule-weighted fallback so we still land on "b".
let c = mk("c", 1);
let pool2: Vec<&dyn Worker> = vec![&a, &b, &c];
let second = r
.pick(
&pool2,
&LocalRequest {
session_id: "user-42".into(),
model: "llama-70b",
expected_tokens: 64,
},
)
.expect("ok")
.id()
.to_string();
assert_eq!(second, "b");
}
#[test]
fn forget_clears_binding() {
let mut r = KvCacheAwareRouter::default();
let a = mk("a", 100);
let pool: Vec<&dyn Worker> = vec![&a];
let _ = r
.pick(
&pool,
&LocalRequest {
session_id: "s".into(),
model: "llama-70b",
expected_tokens: 16,
},
)
.expect("ok");
assert_eq!(r.len(), 1);
r.forget("s");
assert_eq!(r.len(), 0);
}
#[test]
fn stale_binding_falls_back() {
let mut r = KvCacheAwareRouter::default();
let a = mk("a", 200);
let b = mk("b", 50);
let pool: Vec<&dyn Worker> = vec![&a, &b];
let first = r
.pick(
&pool,
&LocalRequest {
session_id: "session-x".into(),
model: "llama-70b",
expected_tokens: 32,
},
)
.expect("ok")
.id()
.to_string();
assert_eq!(first, "b");
// Worker "b" disappears from the pool — fall back to "a".
let pool2: Vec<&dyn Worker> = vec![&a];
let second = r
.pick(
&pool2,
&LocalRequest {
session_id: "session-x".into(),
model: "llama-70b",
expected_tokens: 32,
},
)
.expect("ok")
.id()
.to_string();
assert_eq!(second, "a");
}