tidaldb/tidal-stress/Cargo.toml
jx12n f640764d89 feat(tidal-stress): open-loop capacity load generator (thepeach feed workload)
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).
2026-06-10 21:54:21 -06:00

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"] }