feat: throughput bench across cluster sizes + bench-regress gate #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 . |