Skip to content

feat: throughput bench across cluster sizes + bench-regress gate #5

feat: throughput bench across cluster sizes + bench-regress gate

feat: throughput bench across cluster sizes + bench-regress gate #5

Workflow file for this run

name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
build-and-test:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Install build deps
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential cmake pkg-config \
libprotobuf-dev protobuf-compiler protobuf-compiler-grpc \
libgrpc++-dev libleveldb-dev libssl-dev
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
- name: Build
run: cmake --build build -j "$(nproc)"
- name: Unit + integration tests
run: |
cd build
ctest --output-on-failure -E '^chaos_(smoke|full)$'
- name: Chaos suite (500 scenarios, capped at 540s wall-clock)
run: |
cd build
# Target 500 randomized scenarios. The chaos driver stops early
# if the wall-clock budget is hit; whatever it ran must all pass.
./chaos_test --scenarios=500 --seed=1 --budget-seconds=540 \
--json=chaos_ci.json
# Surface how many scenarios actually executed.
grep -E '"(planned|attempted)_scenarios|"passed|"failed|"budget_hit"' chaos_ci.json || true
- name: Throughput bench (smoke)
run: |
cd build
./throughput_bench --ops=500
- name: Bench regression gate (3/5/7-node scaling, 30% drift)
run: |
cd build
mkdir -p bench_candidate
# Re-run the scaling bench and diff against the committed
# per-N baselines. A short op count keeps CI fast; the gate
# tolerance (30%) absorbs run-to-run variance on shared runners.
./throughput_bench --scaling --ops=1500 --out-dir=bench_candidate
./bench_regress --baseline=../bench/results \
--candidate=bench_candidate --drift=0.30
three-process-integration:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Install build deps
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential cmake pkg-config \
libprotobuf-dev protobuf-compiler protobuf-compiler-grpc \
libgrpc++-dev libleveldb-dev libssl-dev
- name: Build raftkv binary
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DRAFTKV_BUILD_TESTS=OFF
cmake --build build -j "$(nproc)" --target raftkv
- name: Run 3-process cluster, verify processes bind and stay up
shell: bash
run: |
set -euo pipefail
mkdir -p run/n0 run/n1 run/n2
PEERS="0@127.0.0.1:9000,1@127.0.0.1:9010,2@127.0.0.1:9020"
./build/raftkv --node-id 0 --peers "$PEERS" \
--raft-listen 127.0.0.1:9000 --kv-listen 127.0.0.1:9100 \
--data-dir run/n0 > run/n0/log 2>&1 &
PID0=$!
./build/raftkv --node-id 1 --peers "$PEERS" \
--raft-listen 127.0.0.1:9010 --kv-listen 127.0.0.1:9110 \
--data-dir run/n1 > run/n1/log 2>&1 &
PID1=$!
./build/raftkv --node-id 2 --peers "$PEERS" \
--raft-listen 127.0.0.1:9020 --kv-listen 127.0.0.1:9120 \
--data-dir run/n2 > run/n2/log 2>&1 &
PID2=$!
trap 'kill $PID0 $PID1 $PID2 2>/dev/null || true; \
echo "=== n0 ==="; cat run/n0/log; \
echo "=== n1 ==="; cat run/n1/log; \
echo "=== n2 ==="; cat run/n2/log' EXIT
# Allow the cluster to start up and elect.
sleep 8
# All three processes must still be alive (no immediate crash).
kill -0 $PID0
kill -0 $PID1
kill -0 $PID2
# All three ports must be listening.
for port in 9000 9010 9020 9100 9110 9120; do
ss -tln | grep -q ":$port " || (echo "port $port not bound"; exit 1)
done
# At least one node should have logged a "ready" line.
grep -l "raftkv node .* ready" run/n0/log run/n1/log run/n2/log
tsan-stress:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- name: Install build deps
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential cmake pkg-config \
libprotobuf-dev protobuf-compiler protobuf-compiler-grpc \
libgrpc++-dev libleveldb-dev libssl-dev
- name: Configure with ThreadSanitizer
run: |
cmake -S . -B build-tsan -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DRAFTKV_TSAN=ON \
-DRAFTKV_WITH_GRPC=OFF
- name: Build core + tests under TSan
run: cmake --build build-tsan -j "$(nproc)"
- name: Stress unit + 3-node in-process integration under TSan (repeat 3x)
env:
TSAN_OPTIONS: halt_on_error=1:second_deadlock_stack=1:exitcode=66
run: |
cd build-tsan
# The in-process integration tests bring up a 3-node cluster
# with all replication, election, and apply threads in a single
# process. Repeating each test 3x under TSan exercises the
# mutex/atomic ordering across leader churn and replication
# rounds. Skip chaos_full (CI budget) and chaos_smoke (covered
# by main job).
ctest --output-on-failure --timeout 300 \
-E '^(chaos_smoke|chaos_full)$' \
--repeat until-pass:1 --repeat after-timeout:1
# CTest's --repeat does not re-run on success. Invoke each test
# binary directly with --gtest_repeat=3 to get true repeat-3x
# coverage under TSan.
for t in log_test state_machine_test persister_test election_test \
replication_test log_invariants_test \
leader_election_integration replication_integration \
snapshot_integration client_ops_integration; do
echo "=== TSan stress: $t (repeat 3x) ==="
./$t --gtest_repeat=3 --gtest_break_on_failure
done
docker-build:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Build docker image
run: docker build -t raftkv:ci .