mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-24 02:38:06 +02:00
server+bench: AppState::new_with_workload; bench drops set_var, exercises heavy cap
Two cubic findings on bench_actor_isolation.rs flagged together:
P2 (lib.rs:202): `unsafe { std::env::set_var(...) }` ran inside
`#[tokio::main] async fn main()` AFTER the multi-thread tokio runtime
was up. Rust 2024 made `set_var` unsafe because libc's `setenv` is
not thread-safe; concurrent env reads from logging or runtime
internals can race or read torn state.
Fix (correct by design, AGENTS.md rule 9): add a public
`AppState::new_with_workload(uri, db, bearer_tokens, workload)`
constructor that takes a caller-built `WorkloadController`. Tests and
benches override per-actor caps via the constructor instead of
mutating global env. Closes the bug class "tests need to mutate
global env to override AppState defaults."
P2 (lib.rs:130): heavy actor's `oneshot.await` inside the loop
serialized — heavy in-flight count was always 1, so cap=1 never
tripped on the heavy side. The bench validated isolation (light p99
bounded) but didn't demonstrate the rejection path.
Fix: add a `--heavy-concurrency` arg (default 4) and spawn batches
as concurrent tokio tasks bounded by an internal semaphore. With
heavy_concurrency=4 and inflight_cap=1, the bench now reports
heavy_too_many_requests > 0 and heavy_ok == 1 at peak — proving the
gate fires for the heavy actor.
Sample run on local FS (4 light actors × 30 ops, 20 heavy batches ×
50 rows, heavy_concurrency=4, cap=1):
heavy_ok: 1
heavy_too_many_requests: 19
light_ok: 120
light_too_many_requests: 0
light_p99: 565 ms (target < 2 s)
Heavy saturates its own cap; light actors are completely unaffected.
The isolation property is now empirically proven by the rejection
counts rather than just by the latency tail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8e1a8e7d55
commit
22d76dbb40
2 changed files with 111 additions and 31 deletions
|
|
@ -206,6 +206,29 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
|
||||
/// Construct with a caller-provided [`workload::WorkloadController`].
|
||||
/// Tests and benches use this to override per-actor caps without
|
||||
/// mutating global env vars (which is unsafe in Rust 2024 once the
|
||||
/// async runtime is up — `setenv` isn't thread-safe).
|
||||
pub fn new_with_workload(
|
||||
uri: String,
|
||||
db: Omnigraph,
|
||||
bearer_tokens: Vec<(String, String)>,
|
||||
workload: workload::WorkloadController,
|
||||
) -> Self {
|
||||
let bearer_tokens: Vec<(BearerTokenHash, Arc<str>)> = bearer_tokens
|
||||
.into_iter()
|
||||
.map(|(actor, token)| (hash_bearer_token(&token), Arc::<str>::from(actor)))
|
||||
.collect();
|
||||
Self {
|
||||
uri,
|
||||
engine: Arc::new(db),
|
||||
workload: Arc::new(workload),
|
||||
bearer_tokens: Arc::from(bearer_tokens),
|
||||
policy_engine: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn open(uri: impl Into<String>) -> Result<Self> {
|
||||
Self::open_with_bearer_token(uri, None).await
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue