fix: harden concurrency limits and high-RPM runtime paths

Bound request, stream, queue, and shutdown resource lifetimes. Reduce scheduler and Redis hot-path work and isolate database maintenance. Include regression coverage, load probes, and concurrency audit results.
This commit is contained in:
elky
2026-09-10 08:14:58 +08:00
parent 361952ada9
commit ecc16673eb
149 changed files with 27963 additions and 1926 deletions
@@ -13,6 +13,7 @@ aether-crypto.workspace = true
aether-data.workspace = true
aether-data-contracts.workspace = true
aether-gateway = { workspace = true, features = ["testkit"] }
aether-runtime.workspace = true
aether-runtime-state.workspace = true
aether-testkit = { workspace = true, features = ["gateway", "postgres"] }
axum.workspace = true
@@ -18,7 +18,7 @@ use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::routing::any;
use axum::{extract::Request, Json, Router};
use futures_util::{SinkExt, StreamExt};
use futures_util::{stream::FuturesUnordered, SinkExt, StreamExt};
use reqwest::Method;
use serde::Serialize;
use serde_json::json;
@@ -83,6 +83,8 @@ struct CapacityCurvePointResult {
successful_requests: usize,
rejected_requests: usize,
failed_requests: usize,
status_counts: BTreeMap<u16, usize>,
non_success_status_samples: serde_json::Value,
throughput_rps: u64,
p50_ms: u64,
p95_ms: u64,
@@ -112,8 +114,16 @@ struct GateMetricSnapshot {
rejected_total: u64,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_stack_size(8 * 1024 * 1024)
.build()?;
runtime.block_on(run())
}
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("capacity-curve-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
let report = run_suite(&config).await?;
@@ -215,11 +225,11 @@ async fn run_gateway_curve(
.await
.map_err(std::io::Error::other)?;
let duration_ms = started_at.elapsed().as_millis() as u64;
let metrics = capture_gate_metrics(
&format!("{}/_gateway/metrics", gateway.base_url()),
gate_name,
)
.await?;
let samples = gateway
.metric_samples()
.await
.map_err(std::io::Error::other)?;
let metrics = gate_metrics(&samples, gate_name)?;
points.push(capacity_point(
*limit,
total_requests,
@@ -319,6 +329,21 @@ async fn run_tunnel_curve(
let peer = connect_protocol_peer(tunnel.base_url(), config.tunnel_hold).await?;
let total_requests =
total_requests_for_limit(relay_concurrency, config.requests_per_point_multiplier);
let envelope = relay_envelope();
let body_offset =
4 + u32::from_be_bytes(envelope[..4].try_into().expect("metadata length")) as usize;
verify_tunnel_fixture(&tunnel, &envelope, body_offset, config.timeout).await?;
let header_sets = (0..total_requests)
.map(|_| {
let mut headers =
tunnel.relay_headers(&envelope[..body_offset], &envelope[body_offset..]);
headers.insert(
"content-type".to_string(),
"application/octet-stream".to_string(),
);
headers
})
.collect();
let probe = HttpLoadProbeConfig {
url: format!(
"{tunnel_base}{TUNNEL_RELAY_PATH_PREFIX}/node-baseline",
@@ -329,7 +354,8 @@ async fn run_tunnel_curve(
"content-type".to_string(),
"application/octet-stream".to_string(),
)]),
body: Some(relay_envelope()),
header_sets,
body: Some(envelope),
total_requests,
concurrency: relay_concurrency,
timeout: config.timeout,
@@ -350,7 +376,8 @@ async fn run_tunnel_curve(
result,
metrics,
));
drop(peer);
peer.abort();
let _ = peer.await;
}
Ok(CapacityCurveScenarioReport {
@@ -362,6 +389,58 @@ async fn run_tunnel_curve(
})
}
async fn verify_tunnel_fixture(
tunnel: &TunnelHarness,
envelope: &[u8],
body_offset: usize,
timeout: Duration,
) -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::builder().timeout(timeout).build()?;
let url = format!(
"{}{TUNNEL_RELAY_PATH_PREFIX}/{TUNNEL_HARNESS_NODE_ID}",
tunnel.base_url()
);
let unsigned = client.post(&url).body(envelope.to_vec()).send().await?;
if unsigned.status() != StatusCode::FORBIDDEN {
return Err(std::io::Error::other("unsigned tunnel preflight was not rejected").into());
}
let mut signed = client.post(&url).body(envelope.to_vec());
for (name, value) in tunnel.relay_headers(&envelope[..body_offset], &envelope[body_offset..]) {
signed = signed.header(name, value);
}
let signed = signed.build()?;
let mut tampered = signed
.try_clone()
.expect("buffered relay request should clone");
let mut tampered_body = envelope.to_vec();
*tampered_body
.last_mut()
.expect("relay body should be nonempty") ^= 1;
*tampered.body_mut() = Some(tampered_body.into());
if client.execute(tampered).await?.status() != StatusCode::FORBIDDEN {
return Err(std::io::Error::other("tampered tunnel preflight was not rejected").into());
}
let response = client
.execute(
signed
.try_clone()
.expect("buffered relay request should clone"),
)
.await?;
let status = response.status();
let body = response.text().await?;
if status != StatusCode::OK || body != "capacity-tunnel-stream" {
return Err(std::io::Error::other(format!(
"signed tunnel preflight failed: {status}: {body}"
))
.into());
}
if client.execute(signed).await?.status() != StatusCode::FORBIDDEN {
return Err(std::io::Error::other("replayed tunnel preflight was not rejected").into());
}
Ok(())
}
fn capacity_point(
limit: usize,
total_requests: usize,
@@ -395,7 +474,10 @@ fn capacity_point(
duration_ms,
successful_requests,
rejected_requests,
failed_requests: result.failed_requests,
failed_requests: total_requests.saturating_sub(successful_requests + rejected_requests),
status_counts: result.status_counts,
non_success_status_samples: serde_json::to_value(result.non_success_status_samples)
.expect("HTTP status samples should serialize"),
throughput_rps,
p50_ms: result.p50_ms,
p95_ms: result.p95_ms,
@@ -440,27 +522,29 @@ async fn capture_gate_metrics(
let samples = fetch_prometheus_samples(metrics_url)
.await
.map_err(std::io::Error::other)?;
gate_metrics(&samples, gate_name)
}
fn gate_metrics(
samples: &[aether_testkit::PrometheusSample],
gate_name: &str,
) -> Result<GateMetricSnapshot, Box<dyn std::error::Error>> {
let required = |name| {
find_metric_value_u64(samples, name, &[("gate", gate_name)])
.or_else(|| {
find_metric_value_u64(
samples,
&format!("aether_testkit_{name}"),
&[("gate", gate_name)],
)
})
.ok_or_else(|| std::io::Error::other(format!("missing {name} for gate {gate_name}")))
};
Ok(GateMetricSnapshot {
in_flight: find_metric_value_u64(&samples, "concurrency_in_flight", &[("gate", gate_name)])
.unwrap_or_default(),
available_permits: find_metric_value_u64(
&samples,
"concurrency_available_permits",
&[("gate", gate_name)],
)
.unwrap_or_default(),
high_watermark: find_metric_value_u64(
&samples,
"concurrency_high_watermark",
&[("gate", gate_name)],
)
.unwrap_or_default(),
rejected_total: find_metric_value_u64(
&samples,
"concurrency_rejected_total",
&[("gate", gate_name)],
)
.unwrap_or_default(),
in_flight: required("concurrency_in_flight")?,
available_permits: required("concurrency_available_permits")?,
high_watermark: required("concurrency_high_watermark")?,
rejected_total: required("concurrency_rejected_total")?,
})
}
@@ -700,25 +784,35 @@ async fn connect_protocol_peer(
))
.await?;
Ok(tokio::spawn(async move {
while let Some(message) = stream.next().await {
let Ok(message) = message else {
break;
};
match message {
Message::Binary(data)
if handle_binary_frame(&mut sink, data.to_vec(), hold)
.await
.is_err() =>
{
break;
let mut responses = FuturesUnordered::new();
loop {
tokio::select! {
message = stream.next() => {
match message {
Some(Ok(Message::Binary(data))) => {
match handle_binary_frame(&mut sink, data.to_vec()).await {
Ok(Some(stream_id)) => responses.push(async move {
tokio::time::sleep(hold).await;
stream_id
}),
Ok(None) => {},
Err(_) => break,
}
}
Some(Ok(Message::Ping(payload))) => {
if sink.send(Message::Pong(payload)).await.is_err() {
break;
}
}
None | Some(Err(_)) | Some(Ok(Message::Close(_))) => break,
_ => {},
}
}
Message::Ping(payload)
if sink.send(Message::Pong(payload.clone())).await.is_err() =>
{
break;
Some(stream_id) = responses.next(), if !responses.is_empty() => {
if send_protocol_response(&mut sink, stream_id).await.is_err() {
break;
}
}
Message::Close(_) => break,
_ => {}
}
}
let _ = sink.close().await;
@@ -728,13 +822,12 @@ async fn connect_protocol_peer(
async fn handle_binary_frame<S>(
sink: &mut S,
data: Vec<u8>,
hold: Duration,
) -> Result<(), tokio_tungstenite::tungstenite::Error>
) -> Result<Option<u32>, tokio_tungstenite::tungstenite::Error>
where
S: SinkExt<Message, Error = tokio_tungstenite::tungstenite::Error> + Unpin,
{
let Some(header) = protocol::FrameHeader::parse(&data) else {
return Ok(());
return Ok(None);
};
match header.msg_type {
protocol::PING => {
@@ -755,48 +848,57 @@ where
.await?;
}
if header.flags & protocol::FLAG_END_STREAM == 0 {
return Ok(());
return Ok(None);
}
tokio::time::sleep(hold).await;
let response_meta = protocol::ResponseMeta {
status: 200,
headers: vec![(
"content-type".to_string(),
"text/plain; charset=utf-8".to_string(),
)],
};
let response_meta_json =
serde_json::to_vec(&response_meta).expect("response metadata should serialize");
sink.send(Message::Binary(
protocol::encode_frame(
header.stream_id,
protocol::RESPONSE_HEADERS,
0,
&response_meta_json,
)
.into(),
))
.await?;
for chunk in [
b"capacity-".as_slice(),
b"tunnel-".as_slice(),
b"stream".as_slice(),
] {
sink.send(Message::Binary(
protocol::encode_frame(header.stream_id, protocol::RESPONSE_BODY, 0, chunk)
.into(),
))
.await?;
}
sink.send(Message::Binary(
protocol::encode_frame(header.stream_id, protocol::STREAM_END, 0, &[]).into(),
))
.await?;
return Ok(Some(header.stream_id));
}
_ => {}
}
Ok(None)
}
async fn send_protocol_response<S>(
sink: &mut S,
stream_id: u32,
) -> Result<(), tokio_tungstenite::tungstenite::Error>
where
S: SinkExt<Message, Error = tokio_tungstenite::tungstenite::Error> + Unpin,
{
let response_meta = protocol::ResponseMeta {
status: 200,
headers: vec![(
"content-type".to_string(),
"text/plain; charset=utf-8".to_string(),
)],
};
let response_meta_json =
serde_json::to_vec(&response_meta).expect("response metadata should serialize");
sink.send(Message::Binary(
protocol::encode_frame(
stream_id,
protocol::RESPONSE_HEADERS,
0,
&response_meta_json,
)
.into(),
))
.await?;
for chunk in [
b"capacity-".as_slice(),
b"tunnel-".as_slice(),
b"stream".as_slice(),
] {
sink.send(Message::Binary(
protocol::encode_frame(stream_id, protocol::RESPONSE_BODY, 0, chunk).into(),
))
.await?;
}
sink.send(Message::Binary(
protocol::encode_frame(stream_id, protocol::STREAM_END, 0, &[]).into(),
))
.await?;
Ok(())
}
@@ -141,8 +141,13 @@ impl SummaryCollector {
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("dependency-pressure-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
let report = run_suite(&config).await?;
@@ -172,8 +172,13 @@ impl RecoveryCollector {
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("failure-recovery-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
let report = run_suite(&config).await?;
@@ -7,6 +7,7 @@ use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};
use aether_crypto::PythonFernetCompat;
use aether_data::repository::auth::CreateStandaloneApiKeyRecord;
use aether_data::repository::wallet::WalletLookupKey;
use aether_data::{
@@ -16,6 +17,7 @@ use aether_data_contracts::repository::global_models::{
CreateAdminGlobalModelRecord, UpdateAdminGlobalModelRecord, UpsertAdminProviderModelRecord,
};
use aether_data_contracts::repository::provider_catalog::{
ProviderCatalogKeyAdminCasUpdate, ProviderCatalogKeyOAuthCredentialFence,
StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider,
};
use serde_json::json;
@@ -200,6 +202,12 @@ impl Config {
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = Config::from_env_and_args().map_err(|err| format!("invalid config: {err}"))?;
let encryption_key = env_value("AETHER_GATEWAY_DATA_ENCRYPTION_KEY")
.or_else(|| env_value("ENCRYPTION_KEY"))
.ok_or(
"set AETHER_GATEWAY_DATA_ENCRYPTION_KEY or ENCRYPTION_KEY to the gateway's encryption key before seeding",
)?;
let secret_cipher = PythonFernetCompat::from_secret(&encryption_key);
let backends = DataBackends::from_config(DataLayerConfig::from_database(SqlDatabaseConfig {
driver: DatabaseDriver::Postgres,
@@ -215,10 +223,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
},
}))?;
seed_provider_catalog(&backends, &config).await?;
seed_provider_catalog(&backends, &config, &secret_cipher).await?;
seed_models(&backends, &config).await?;
let operator_user_id = seed_operator_user(&backends, &config).await?;
seed_api_keys(&backends, &config, &operator_user_id).await?;
seed_api_keys(&backends, &config, &operator_user_id, &secret_cipher).await?;
verify_candidate_selection(&backends, &config).await?;
write_outputs(&config)?;
@@ -243,6 +251,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn seed_provider_catalog(
backends: &DataBackends,
config: &Config,
secret_cipher: &PythonFernetCompat,
) -> Result<(), Box<dyn std::error::Error>> {
let reader = backends
.read()
@@ -326,7 +335,7 @@ async fn seed_provider_catalog(
)?
.with_transport_fields(
Some(json!(["openai:chat"])),
Some(config.provider_api_key.clone()),
Some(secret_cipher.encrypt_plaintext(&config.provider_api_key)?),
None,
None,
None,
@@ -341,17 +350,40 @@ async fn seed_provider_catalog(
Some(json!({"openai:chat": {"state": "closed"}})),
);
if reader
.list_keys_by_ids(std::slice::from_ref(&config.provider_key_id))
.await?
.is_empty()
{
writer.create_key(&provider_key).await?;
} else {
writer.update_key(&provider_key).await?;
for _ in 0..8 {
let existing = reader
.list_keys_by_ids(std::slice::from_ref(&config.provider_key_id))
.await?
.into_iter()
.next();
let Some(existing) = existing else {
writer.create_key(&provider_key).await?;
return Ok(());
};
if existing.provider_id != config.provider_id {
return Err("existing pressure provider key belongs to a different provider".into());
}
// Randomized ciphertext changes on every seed. Fence against the observed
// credential and preserve runtime fields when rotating the configured key.
let update = ProviderCatalogKeyAdminCasUpdate {
expected_encrypted_auth_config: existing.encrypted_auth_config.clone(),
expected_credential: ProviderCatalogKeyOAuthCredentialFence {
encrypted_api_key: existing.encrypted_api_key,
auth_type: existing.auth_type,
provider_id: existing.provider_id,
provider_type: provider.provider_type.clone(),
},
key: provider_key.clone(),
codex_rotation: None,
reset_oauth_runtime: true,
};
if writer.compare_and_update_key_admin_state(&update).await? {
return Ok(());
}
}
Ok(())
Err("pressure provider key changed repeatedly during seed; retry initialization".into())
}
fn pressure_provider_transport_config(mock_upstream_h2c: bool) -> Option<serde_json::Value> {
@@ -466,9 +498,10 @@ async fn seed_api_keys(
backends: &DataBackends,
config: &Config,
operator_user_id: &str,
secret_cipher: &PythonFernetCompat,
) -> Result<(), Box<dyn std::error::Error>> {
for index in 0..config.api_key_count {
seed_api_key(backends, config, operator_user_id, index).await?;
seed_api_key(backends, config, operator_user_id, index, secret_cipher).await?;
}
Ok(())
}
@@ -478,6 +511,7 @@ async fn seed_api_key(
config: &Config,
operator_user_id: &str,
key_index: usize,
secret_cipher: &PythonFernetCompat,
) -> Result<(), Box<dyn std::error::Error>> {
let auth_reader = backends
.read()
@@ -494,17 +528,28 @@ async fn seed_api_key(
let api_key_id = pressure_api_key_id(config, key_index);
let api_key_value = pressure_api_key_value(config, key_index);
let key_hash = sha256_hex(&api_key_value);
let key_encrypted = secret_cipher.encrypt_plaintext(&api_key_value)?;
let existing = auth_reader
.find_export_standalone_api_key_by_id(&api_key_id)
.await?;
if existing
.as_ref()
.is_some_and(|record| record.key_hash != key_hash)
{
return Err(format!(
"existing pressure API key {api_key_id} has a different hash; use its original value or a new --api-key-id"
)
.into());
}
if existing.is_none() {
auth_writer
.create_standalone_api_key(CreateStandaloneApiKeyRecord {
user_id: operator_user_id.to_string(),
api_key_id: api_key_id.clone(),
key_hash: sha256_hex(&api_key_value),
key_encrypted: Some(api_key_value),
key_hash,
key_encrypted: Some(key_encrypted),
name: Some(format!("Local pressure API key {}", key_index + 1)),
allowed_providers: Some(vec![config.provider_id.clone()]),
allowed_api_formats: Some(vec!["openai:chat".to_string()]),
@@ -526,8 +571,8 @@ async fn seed_api_key(
.update_standalone_api_key_basic(
aether_data::repository::auth::UpdateStandaloneApiKeyBasicRecord {
api_key_id: api_key_id.clone(),
key_encrypted: None,
key_encrypted_present: false,
key_encrypted: Some(key_encrypted),
key_encrypted_present: true,
name: Some(format!("Local pressure API key {}", key_index + 1)),
name_present: true,
force_capabilities: None,
@@ -867,6 +912,8 @@ fn print_help() {
println!(
"Usage: cargo run -p aether-integration-tests --bin gateway_pressure_seed -- [options]\n\
\n\
The seed and gateway must share AETHER_GATEWAY_DATA_ENCRYPTION_KEY (or ENCRYPTION_KEY).\n\
\n\
Options:\n\
--database-url URL\n\
--output-env PATH\n\
@@ -104,8 +104,13 @@ struct AcceptanceReport {
reasons: Vec<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("gateway-tunnel-stream-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
let report = run_suite(&config).await?;
@@ -318,8 +318,13 @@ struct ProtocolPeer {
stats: Arc<PeerStats>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("llm-stream-stability-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
config.validate().map_err(std::io::Error::other)?;
@@ -441,6 +441,7 @@ async fn chat_completions(State(app): State<App>, request: axum::extract::Reques
completion
.take()
.expect("request completion guard should be present"),
false,
);
}
@@ -457,6 +458,14 @@ async fn chat_completions(State(app): State<App>, request: axum::extract::Reques
};
let stream = request_wants_stream(&body);
if stream {
let include_usage = serde_json::from_slice::<serde_json::Value>(&body)
.ok()
.and_then(|value| {
value
.pointer("/stream_options/include_usage")
.and_then(serde_json::Value::as_bool)
})
.unwrap_or(false);
record_response_header_created(&app, request_started.started_at.elapsed());
return build_chat_sse_response(
app,
@@ -464,6 +473,7 @@ async fn chat_completions(State(app): State<App>, request: axum::extract::Reques
completion
.take()
.expect("request completion guard should be present"),
include_usage,
);
}
// A stream truncation profile only applies after the request is known to be streaming.
@@ -609,6 +619,7 @@ fn build_chat_sse_response(
app: App,
profile: RequestProfile,
completion: RequestCompletionGuard,
include_usage: bool,
) -> Response {
let response_created_at = Instant::now();
let config = app.config.clone();
@@ -659,6 +670,21 @@ fn build_chat_sse_response(
yield Ok::<Bytes, std::io::Error>(Bytes::from(
"data: {\"choices\":[{\"index\":0,\"delta\":{},\"finish_reason\":\"stop\"}]}\n\n",
));
if include_usage {
let payload = json!({
"id": "chatcmpl-mock",
"object": "chat.completion.chunk",
"created": current_unix_secs(),
"model": "mock-model",
"choices": [],
"usage": {
"prompt_tokens": 1,
"completion_tokens": config.chunks.max(1),
"total_tokens": config.chunks.max(1) + 1
}
});
yield Ok::<Bytes, std::io::Error>(Bytes::from(format!("data: {payload}\n\n")));
}
yield Ok::<Bytes, std::io::Error>(Bytes::from("data: [DONE]\n\n"));
if let Some(completion) = completion.take() {
completion.complete();
@@ -1465,7 +1491,11 @@ mod tests {
) {
let response = client
.post(url)
.json(&json!({"stream": true, "model": "mock-test"}))
.json(&json!({
"stream": true,
"model": "mock-test",
"stream_options": {"include_usage": true}
}))
.send()
.await
.expect("headers should arrive before the body error");
@@ -1505,6 +1535,78 @@ mod tests {
!body.contains("[DONE]"),
"truncated stream must not emit [DONE]"
);
assert!(
!body.contains("\"usage\""),
"truncated stream must not emit terminal usage"
);
}
#[tokio::test]
async fn chat_stream_usage_is_opt_in_and_precedes_done() {
for chunks in [0, 3] {
for (include_usage, assume_stream) in [
(None, false),
(Some(false), false),
(Some(true), false),
(Some(true), true),
] {
let config = Config {
chunks,
chunk_delay: Duration::ZERO,
assume_stream,
..Default::default()
};
let app = App {
metrics: Arc::new(Metrics::for_binds(&config.binds)),
bind_label: Arc::from(config.binds[0].to_string()),
config,
};
let mut payload = json!({"stream": true, "model": "mock-test"});
if let Some(include_usage) = include_usage {
payload["stream_options"] = json!({"include_usage": include_usage});
}
let request = axum::http::Request::builder()
.body(Body::from(payload.to_string()))
.unwrap();
let response = chat_completions(State(app), request).await;
assert_eq!(response.status(), StatusCode::OK);
let body = to_bytes(response.into_body(), 16 * 1024).await.unwrap();
let body = std::str::from_utf8(&body).unwrap();
let frames = body
.split("\n\n")
.filter_map(|frame| frame.strip_prefix("data: "))
.collect::<Vec<_>>();
assert_eq!(frames.last(), Some(&"[DONE]"));
let payloads = frames[..frames.len() - 1]
.iter()
.map(|frame| serde_json::from_str::<serde_json::Value>(frame).unwrap())
.collect::<Vec<_>>();
let usage_chunks = payloads
.iter()
.filter(|payload| payload.get("usage").is_some())
.collect::<Vec<_>>();
if include_usage == Some(true) && !assume_stream {
assert_eq!(usage_chunks.len(), 1);
assert_eq!(payloads.last(), Some(usage_chunks[0]));
assert_eq!(usage_chunks[0]["object"], "chat.completion.chunk");
assert_eq!(usage_chunks[0]["choices"], json!([]));
assert_eq!(
usage_chunks[0]["usage"],
json!({
"prompt_tokens": 1,
"completion_tokens": chunks.max(1),
"total_tokens": chunks.max(1) + 1
})
);
assert_eq!(
payloads[payloads.len() - 2]["choices"][0]["finish_reason"],
"stop"
);
} else {
assert!(usage_chunks.is_empty());
}
}
}
}
async fn wait_for_completed(metrics: &Metrics, expected: u64) {
@@ -94,8 +94,13 @@ struct WebSocketAdmissionProbeResult {
runtime: BenchmarkRuntimeSnapshot,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("multi-instance-admission-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
let report = run_suite(&config).await?;
@@ -66,8 +66,13 @@ struct RelayOverheadSnapshot {
mean_delta_ms: i64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("multi-instance-owner-relay-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
let report = run_suite(&config).await?;
@@ -54,8 +54,13 @@ struct SingleInstanceBaselineReport {
scenarios: Vec<NamedBaselineResult>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("single-instance-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
let report = run_suite(&config).await?;
@@ -123,8 +123,13 @@ struct LockSample {
oldest_lock_wait_ms: i64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("usage-aux-counter-hotspot-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
@@ -116,8 +116,13 @@ struct LockSample {
oldest_lock_wait_ms: i64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("usage-counter-hotspot-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
@@ -453,6 +458,7 @@ fn usage_record(index: usize) -> UpsertUsageRecord {
let now_ms = now_unix_ms().saturating_add(index as u64);
let now_secs = now_ms / 1_000;
UpsertUsageRecord {
capture_retention: Default::default(),
request_id: format!("usage-hotspot-{index:08}"),
user_id: Some("user-hotspot".to_string()),
api_key_id: Some("api-key-hotspot".to_string()),
@@ -18,6 +18,8 @@ use sqlx::{PgPool, Row};
use tokio::sync::Mutex;
const PROVIDER_ID: &str = "provider-hotspot";
const USER_ID: &str = "settlement-hotspot-user";
const WALLET_ID: &str = "settlement-hotspot-wallet";
const REQUEST_PREFIX: &str = "settlement-hotspot";
const COST_PER_REQUEST_USD: f64 = 0.001;
@@ -99,6 +101,7 @@ struct CounterReport {
provider_monthly_outbox_rows: i64,
provider_monthly_used_usd: f64,
expected_provider_monthly_used_usd: f64,
wallet_consumed_usd: f64,
}
#[derive(Debug, Serialize, Clone, Copy, Default)]
@@ -120,8 +123,13 @@ struct LockSample {
oldest_lock_wait_ms: i64,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _log_shutdown = aether_runtime::LogShutdownGuard::new();
run()
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn run() -> Result<(), Box<dyn std::error::Error>> {
init_test_runtime_for("usage-settlement-hotspot-baseline");
let config = parse_args(std::env::args().skip(1).collect())?;
@@ -239,6 +247,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
std::fs::write(path, format!("{raw}\n"))?;
}
if report.failed_requests != 0
|| report.counters.settled_usage_rows != config.requests as i64
|| report.counters.settlement_snapshot_rows != config.requests as i64
|| report.counters.outbox_pending_rows != 0
|| (report.counters.provider_monthly_used_usd
- report.counters.expected_provider_monthly_used_usd)
.abs()
> 1e-8
|| (report.counters.wallet_consumed_usd
- report.counters.expected_provider_monthly_used_usd)
.abs()
> 1e-8
{
return Err(std::io::Error::other(
"settlement baseline failed correctness checks; see report",
)
.into());
}
Ok(())
}
@@ -388,6 +414,24 @@ async fn wait_for_outbox_drain(
}
async fn seed_settlement_rows(pool: &PgPool, requests: usize) -> Result<(), sqlx::Error> {
sqlx::query(
"INSERT INTO users (id, username, email_verified) VALUES ($1, $1, true) ON CONFLICT (id) DO NOTHING",
)
.bind(USER_ID)
.execute(pool)
.await?;
sqlx::query(
r#"
INSERT INTO wallets (id, user_id, balance, gift_balance, total_consumed, created_at, updated_at)
VALUES ($1, $2, $3, 0, 0, NOW(), NOW())
ON CONFLICT (id) DO UPDATE SET balance = EXCLUDED.balance, gift_balance = 0, total_consumed = 0
"#,
)
.bind(WALLET_ID)
.bind(USER_ID)
.bind(requests as f64 * COST_PER_REQUEST_USD + 1.0)
.execute(pool)
.await?;
sqlx::query(
r#"
INSERT INTO providers (id, name, provider_type, monthly_used_usd)
@@ -432,6 +476,7 @@ WHERE request_id LIKE $1
INSERT INTO "usage" (
id,
request_id,
user_id,
provider_name,
model,
provider_id,
@@ -445,6 +490,7 @@ INSERT INTO "usage" (
SELECT
'settlement-usage-' || LPAD(gs::TEXT, 8, '0'),
$2 || '-' || LPAD(gs::TEXT, 8, '0'),
$7,
'Hotspot Provider',
'gpt-5',
$3,
@@ -463,6 +509,7 @@ FROM generate_series(0, $1::INTEGER - 1) AS gs
.bind(COST_PER_REQUEST_USD)
.bind(now_unix_ms() as i64)
.bind(now_unix_secs() as i64)
.bind(USER_ID)
.execute(pool)
.await?;
@@ -472,7 +519,7 @@ FROM generate_series(0, $1::INTEGER - 1) AS gs
fn settlement_input(index: usize) -> UsageSettlementInput {
UsageSettlementInput {
request_id: format!("{REQUEST_PREFIX}-{index:08}"),
user_id: None,
user_id: Some(USER_ID.to_string()),
api_key_id: None,
api_key_is_standalone: false,
provider_id: Some(PROVIDER_ID.to_string()),
@@ -552,11 +599,13 @@ SELECT
SELECT CAST(monthly_used_usd AS DOUBLE PRECISION)
FROM providers
WHERE id = $2
) AS provider_monthly_used_usd
) AS provider_monthly_used_usd,
(SELECT CAST(total_consumed AS DOUBLE PRECISION) FROM wallets WHERE id = $3) AS wallet_consumed_usd
"#,
)
.bind(format!("{REQUEST_PREFIX}-%"))
.bind(PROVIDER_ID)
.bind(WALLET_ID)
.fetch_one(pool)
.await?;
Ok(CounterReport {
@@ -568,6 +617,7 @@ SELECT
provider_monthly_outbox_rows: row.try_get("provider_monthly_outbox_rows")?,
provider_monthly_used_usd: row.try_get("provider_monthly_used_usd")?,
expected_provider_monthly_used_usd: (requests as f64) * COST_PER_REQUEST_USD,
wallet_consumed_usd: row.try_get("wallet_consumed_usd")?,
})
}