transport: complete M0–M7
Some checks failed
ci / rust (push) Failing after 2m21s
ci / ui (push) Failing after 28s
images / build-and-push (push) Failing after 18s

shared: add stream+consumer policy helpers; NATS context header builder

aggregate/runner/projection: centralize stream validation and header usage; set bounded consumer params

projection: add QueryService gRPC and wire into main; settings include PROJECTION_GRPC_ADDR

gateway: gRPC routing to Projection/Runner with deadlines; bounded read-only retries; pooled gRPC channels (bounded LRU+TTL); admin proxy forwards to gRPC; probes use concurrency limiter + TTL cache

runner: add RunnerAdmin gRPC server (drain, status, reload) and wire into main; settings include RUNNER_GRPC_ADDR

tests: add gateway authz for runner admin, projection tenant isolation, runner admin drain semantics

docs: update TRANSPORT_DEVELOPMENT_PLAN to reflect completed milestones and details
This commit is contained in:
2026-03-30 14:24:14 +03:00
parent 1ab112438b
commit 90c307016d
41 changed files with 2391 additions and 505 deletions

View File

@@ -13,6 +13,7 @@ metrics-exporter-prometheus = "0.16.0"
reqwest = { version = "0.12.23", default-features = false, features = ["json", "rustls-tls"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
shared = { path = "../../shared" }
thiserror = "2.0.16"
tokio = { version = "1.45.0", features = ["macros", "net", "process", "rt-multi-thread", "signal", "time"] }
tower-http = { version = "0.6.6", features = ["trace"] }

View File

@@ -19,7 +19,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;
const HEADER_IDEMPOTENCY_KEY: &str = "idempotency-key";
const HEADER_TENANT_ID: &str = "x-tenant-id";
const HEADER_TENANT_ID: &str = shared::HEADER_X_TENANT_ID;
pub fn admin_router() -> Router<AppState> {
Router::new()

View File

@@ -50,12 +50,12 @@ pub async fn snapshot_with_context(
async fn get_ok(client: &reqwest::Client, url: &str, ctx: Option<&RequestIds>) -> bool {
let mut req = client.get(url).timeout(Duration::from_secs(2));
if let Some(ctx) = ctx {
req = req.header("x-request-id", &ctx.request_id);
req = req.header(shared::HEADER_X_REQUEST_ID, &ctx.request_id);
if let Some(cid) = &ctx.correlation_id {
req = req.header("x-correlation-id", cid);
req = req.header(shared::HEADER_X_CORRELATION_ID, cid);
}
if let Some(tp) = &ctx.traceparent {
req = req.header("traceparent", tp);
req = req.header(shared::HEADER_TRACEPARENT, tp);
}
}

View File

@@ -53,9 +53,9 @@ pub struct RequestIds {
pub traceparent: Option<String>,
}
const HEADER_REQUEST_ID: HeaderName = HeaderName::from_static("x-request-id");
const HEADER_CORRELATION_ID: HeaderName = HeaderName::from_static("x-correlation-id");
const HEADER_TRACEPARENT: HeaderName = HeaderName::from_static("traceparent");
const HEADER_REQUEST_ID: HeaderName = HeaderName::from_static(shared::HEADER_X_REQUEST_ID);
const HEADER_CORRELATION_ID: HeaderName = HeaderName::from_static(shared::HEADER_X_CORRELATION_ID);
const HEADER_TRACEPARENT: HeaderName = HeaderName::from_static(shared::HEADER_TRACEPARENT);
pub fn build_app(state: AppState) -> Router {
let trace = TraceLayer::new_for_http()