New workspace crate: an open-loop, coordinated-omission-corrected HTTP load generator + capacity ramp for the standalone and multi-process cluster surfaces, modeling a thepeach feed session (feed reads + view/like/skip signals + search, signal-dominated per their user-graph spec). Throttleable target rate, ramp presets (smoke/quick/peach-100k/max) or rps:secs specs, peach/reads/writes/custom mixes, leader vs sharded write paths, per-op p50/p90/p99/p999/max latency, a backpressure-aware status breakdown (429/408/503/4xx/5xx/transport), and a verdict translated to supported DAU. Runs in-cluster as a k8s Job (tidal-stress/k8s/). Open-loop scheduler (scheduler.rs) fires at a fixed arrival rate and measures latency from each request's intended send time, so a server stall inflates the percentiles a closed-loop test hides; it shed-and-counts rather than blocking when the in-flight cap is reached. Pure-Rust (tokio + reqwest/rustls), no engine deps. Findings on the live 3-region k3s cluster (docs/ops/stress-test-thepeach.md): reads scale to thousands/s at <15ms p99; the replicated /signals path saturates at ~90 signals/s (single-leader funnel + 2-worker write pool + synchronous gRPC ship); the sharded path sustains 3,669 signals/s at 0 errors and ~27% cluster CPU (≈ the 100k-DAU peak, knee not reached). Overload degrades gracefully (429; 0 pod restarts). thepeach's planned in-process embedding sidesteps all of it (write ≈82ns).
57 lines
2.7 KiB
TOML
57 lines
2.7 KiB
TOML
[package]
|
|
name = "tidal-stress"
|
|
version = "0.1.0"
|
|
edition.workspace = true
|
|
rust-version.workspace = true
|
|
description = "Open-loop load generator + capacity ramp for tidalDB's HTTP surface (standalone + multi-process cluster), modeling a thepeach-style feed workload"
|
|
license.workspace = true
|
|
|
|
# ── tidal-crate lint posture (single source of truth) ──────────────────────
|
|
# IDENTICAL block across tidaldb / tidal-net / tidal-server / tidalctl. These
|
|
# crates deliberately DO NOT inherit `[workspace.lints]`; they hold the embedded
|
|
# recommendation DB + its transport/server/CLI to a stricter correctness bar
|
|
# (`unsafe_code = forbid`, `clippy::all = deny`, `unwrap_used = deny`).
|
|
# `unwrap_used = "deny"` is kept per-crate rather than in `[workspace.lints]`
|
|
# because the workspace also hosts the example/consumer crates under
|
|
# `applications/` (not held to the engine's bar). Keep these four blocks BYTE-IDENTICAL.
|
|
[lints.rust]
|
|
unsafe_code = "forbid"
|
|
|
|
[lints.clippy]
|
|
all = { level = "deny", priority = -1 }
|
|
pedantic = { level = "warn", priority = -1 }
|
|
nursery = { level = "warn", priority = -1 }
|
|
# Justified allows: latency/rate math is pervasive usize<->u64<->f64 casting (a
|
|
# load generator is nothing but counters and durations), so the lossy-cast
|
|
# pedantic family is allowed exactly as the engine's ranking math allows it.
|
|
cast_possible_truncation = "allow"
|
|
cast_possible_wrap = "allow"
|
|
cast_precision_loss = "allow"
|
|
cast_sign_loss = "allow"
|
|
module_name_repetitions = "allow"
|
|
# Advisory pedantic/nursery style lints that are noise for a CLI load tool (and
|
|
# which the engine crates already run at warn, not deny): help-text URLs/flags
|
|
# read fine bare; `out.push_str(&format!(..))` is the clearest way to assemble a
|
|
# report table; constructors take their config by value; const-ness of trivial
|
|
# accessors churns. Correctness lints (clippy::all) stay DENY.
|
|
doc_markdown = "allow"
|
|
format_push_string = "allow"
|
|
needless_pass_by_value = "allow"
|
|
missing_const_for_fn = "allow"
|
|
map_unwrap_or = "allow"
|
|
unwrap_used = "deny"
|
|
|
|
[dependencies]
|
|
clap = { version = "4.5", features = ["derive", "env"] }
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
thiserror = "2"
|
|
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "time", "signal"] }
|
|
tracing = "0.1"
|
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
rand = "0.9"
|
|
# Async HTTP only (no blocking client): rustls posture matches tidal-server /
|
|
# tidal-net — drops the OpenSSL/native-tls system dependency for a clean static
|
|
# build. `json` for the typed request/response bodies.
|
|
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|