Files
datastore/ci/jobs/scripts/ingest_keeper_metrics.py
zlareb1andClaude Sonnet 4.6 35e48faf43 keeper stress: add Keeper stress test framework
Adds a stress testing framework for ClickHouse Keeper under
`tests/stress/keeper/`, wired into CI (PR gate + nightly workflows).

Key components:
- Workloads: `keeper_bench.py` runner with YAML-defined workload profiles
  (`prod_mix.yaml`, `read_requests.yaml`, `write_requests.yaml`, etc.)
- Scenarios: `core_no_faults.yaml` and `core_faults.yaml` with netem-based
  network fault injection (latency, jitter, packet loss)
- Fault framework: `faults/network.py` (netem), `faults/base.py` (step
  dispatcher with `kind: parallel` support)
- Metrics: `MetricsSampler` collects keeper stats, `sink.py` writes JSONL,
  ingested into CIDB via `ingest_keeper_metrics.py` post-hook
- Gates: scenario pass/fail conditions based on RPS, p99 latency, error rate
- Grafana dashboards for run details, 1vs1 comparison, historical progression

CI integration:
- PR job: 3 no-fault scenarios (prod-mix, read-multi, write-multi), ARM_LARGE,
  15 min each, runs when `src/Coordination/` or stress test files change
- Nightly (no-faults): all no-fault scenarios, default + rocks backends, ARM_LARGE
- Nightly (faults): all fault scenarios, default + rocks backends, ARM_LARGE
- Single `keeper_stress_job` config; mode detected via `Info().pr_number` and
  `Info().workflow_name` inside the job script

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-21 16:08:00 +00:00

37 lines
1.0 KiB
Python

#!/usr/bin/env python3
"""Post-hook script: ingest keeper_metrics.jsonl into CIDB after a keeper stress job."""
import os
import sys
from pathlib import Path
_repo_dir = str(Path(__file__).resolve().parents[3])
_ci_dir = str(Path(__file__).resolve().parents[2])
for _p in (_repo_dir, _ci_dir):
if _p not in sys.path:
sys.path.insert(0, _p)
from praktika.settings import Settings
from praktika.utils import Utils
from ci.jobs.scripts.cidb_cluster import CIDBCluster
def main():
metrics_file = os.environ.get(
"KEEPER_METRICS_FILE",
f"{Utils.absolute_path(Settings.TEMP_DIR)}/keeper_metrics.jsonl",
)
if not os.path.exists(metrics_file):
print(f"NOTE: keeper metrics file not found at {metrics_file!r}, skipping ingestion")
return
ci_db = CIDBCluster()
inserted, _ = ci_db.insert_keeper_metrics_from_file(
file_path=metrics_file,
chunk_size=1000,
)
print(f"NOTE: keeper metrics ingested: file={metrics_file} inserted={inserted}")
if __name__ == "__main__":
main()