Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
58d92af
feat(phase-92): add observability infrastructure
TinDang97 Apr 9, 2026
9e13462
feat(phase-94): durability proof test infrastructure
TinDang97 Apr 9, 2026
a50ebb5
test(phase-95): replication hardening test suite
TinDang97 Apr 9, 2026
1114eb0
feat(phase-96): client compatibility matrix CI + docs
TinDang97 Apr 9, 2026
422bdc5
ci(phase-97): add Criterion performance regression gate
TinDang97 Apr 9, 2026
7bb7c68
feat(phase-98): security hardening — deny, threat model, Lua audit, S…
TinDang97 Apr 9, 2026
da6fa77
docs(phase-99): release engineering — versioning, runbooks
TinDang97 Apr 9, 2026
4b4e88c
style: rustfmt formatting fixes for phase 92-99 code
TinDang97 Apr 9, 2026
d49908f
feat(phase-92): wire Prometheus metrics into dispatch + connection li…
TinDang97 Apr 9, 2026
de1ce57
test(phase-94+95): add disk-offload crash, Jepsen-lite, full-resync, …
TinDang97 Apr 9, 2026
860c4df
ci(phase-96+97): expand compat matrix, bench gate, RSS gate, SBOM, co…
TinDang97 Apr 9, 2026
de38da1
docs(phase-98+99): TLS cipher freeze, TLS rotation runbook, rolling r…
TinDang97 Apr 9, 2026
b6ea3b9
feat(phase-92): add /healthz + /readyz, extend INFO, wire SLOWLOG + t…
TinDang97 Apr 9, 2026
9000410
fix(phase-89): fix RESP parser crash on bare LF in frame count
TinDang97 Apr 9, 2026
957b8b9
fix(phase-90): eradicate remaining un-annotated unwrap/expect in hot-…
TinDang97 Apr 9, 2026
2a14ec1
fix(tests): address PR review — SAFETY comments, Stdio::null, bulk re…
TinDang97 Apr 9, 2026
b167f83
fix(slowlog+dispatch): address PR review — dispatch routing, threshol…
TinDang97 Apr 9, 2026
1a73402
fix(admin+parse+main): address PR review — unwrap removal, check-conf…
TinDang97 Apr 9, 2026
7460f5e
style: formatting cleanup from PR review fix agents
TinDang97 Apr 9, 2026
286297f
ci(bench-gate): add actual regression detection against cached baseline
TinDang97 Apr 9, 2026
ba8b0f7
refactor: complete RuntimeConfig RwLock migration to parking_lot
TinDang97 Apr 9, 2026
c9de982
fix: correct RuntimeConfig RwLock test return type in acl.rs
TinDang97 Apr 9, 2026
8d6ad19
feat(phase-105): CHANGELOG gate + user docs + release pipeline enhanc…
TinDang97 Apr 9, 2026
a7d8059
feat(phases-103-104): gap closure — jepsen-lite, redis compat, memory…
TinDang97 Apr 9, 2026
2a3b5d7
feat(phase-101): add HEALTHZ + READYZ commands to dispatch table
TinDang97 Apr 9, 2026
7064236
fix(gap-closure): wire metrics into all handlers, add repl lag metric
TinDang97 Apr 9, 2026
b2db619
fix(pr-review): address 3 HIGH blockers from security review
TinDang97 Apr 9, 2026
02f02e4
fix: rustfmt + CHANGELOG entry for phases 92-105
TinDang97 Apr 9, 2026
c628caa
fix(pr-review): address remaining review comments from PR #65
TinDang97 Apr 9, 2026
f75e212
fix(pr-review): address all remaining PR #65 review issues
TinDang97 Apr 9, 2026
d33e9f6
fix(ci): go-redis compat test fails in /tmp (system temp root)
TinDang97 Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions .github/workflows/bench-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
name: Performance Gate

on:
push:
branches: [main]
paths:
- 'src/**'
- 'Cargo.toml'
- 'benches/**'
pull_request:
branches: [main]
paths:
- 'src/**'
- 'Cargo.toml'
- 'benches/**'

env:
CARGO_TERM_COLOR: always
MOON_NO_URING: "1"
# Regression threshold: fail if any critical bench regresses beyond this %
REGRESSION_THRESHOLD: "5"

jobs:
bench-regression:
name: Criterion Regression Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- uses: dtolnay/rust-toolchain@1.94.0
- uses: Swatinem/rust-cache@v2

# Restore baseline from main branch (if available)
- name: Restore baseline
id: baseline
uses: actions/cache/restore@v4
with:
path: target/criterion
key: criterion-baseline-main

- name: Run critical benchmarks
run: |
cargo bench --no-default-features --features runtime-tokio,jemalloc \
--bench get_hotpath \
--bench dispatch_baseline \
--bench resp_parsing \
--bench pubsub_hotpath \
--bench distance_bench \
--bench hnsw_bench \
--bench fwht_bench \
--bench entry_memory \
--bench compact_key \
--bench bptree_memory \
-- --output-format bencher 2>&1 | tee bench_results.txt

- name: Check for benchmark failures
run: |
if [ ! -s bench_results.txt ]; then
echo "ERROR: Benchmark output is empty — benchmarks may have failed to run."
exit 1
fi
if grep -qi 'error\|panicked\|FAILED' bench_results.txt; then
echo "ERROR: Benchmark run contained errors:"
grep -i 'error\|panicked\|FAILED' bench_results.txt
exit 1
fi
echo "Benchmarks completed successfully."

- name: Check for regressions
if: steps.baseline.outputs.cache-hit == 'true' && github.event_name == 'pull_request'
run: |
echo "Checking for regressions against main baseline..."
echo ""

# Criterion stores results in target/criterion/<bench>/new/estimates.json
# Parse bencher-format output for ns/iter values and compare
FAILED=0
CRITICAL_BENCHES="get_hotpath dispatch_baseline resp_parsing"

for bench in $CRITICAL_BENCHES; do
# Extract current ns/iter from bencher output
CURRENT=$(grep "^test ${bench}" bench_results.txt | grep -oP '[\d,]+(?= ns/iter)' | tr -d ',')
if [ -z "$CURRENT" ]; then
# Try alternate format: "bench_name time: [low est high]"
CURRENT=$(grep "${bench}" bench_results.txt | grep -oP '[\d.]+(?= ns)' | head -1)
fi

# Look for baseline estimate from Criterion's cached data
BASELINE_FILE="target/criterion/${bench}/base/estimates.json"
if [ -f "$BASELINE_FILE" ]; then
BASELINE=$(python3 -c "
import json
with open('${BASELINE_FILE}') as f:
d = json.load(f)
print(int(d.get('mean', d.get('median', {})).get('point_estimate', 0)))
" 2>/dev/null || echo "")
else
BASELINE=""
fi

if [ -n "$CURRENT" ] && [ -n "$BASELINE" ] && [ "$BASELINE" -gt 0 ] 2>/dev/null; then
DELTA=$(( (CURRENT - BASELINE) * 100 / BASELINE ))
if [ "$DELTA" -gt "$REGRESSION_THRESHOLD" ]; then
echo "REGRESSION: ${bench} — ${DELTA}% slower (${BASELINE} → ${CURRENT} ns/iter, threshold: ${REGRESSION_THRESHOLD}%)"
FAILED=1
else
echo "OK: ${bench} — ${DELTA}% change (${BASELINE} → ${CURRENT} ns/iter)"
fi
else
echo "SKIP: ${bench} — no baseline available for comparison"
fi
done

echo ""
if [ "$FAILED" -eq 1 ]; then
echo "FAILED: Critical benchmark regression detected. Fix the regression or update the baseline."
exit 1
else
echo "PASSED: No critical regressions found."
fi

- name: No baseline available (first run)
if: steps.baseline.outputs.cache-hit != 'true' && github.event_name == 'pull_request'
run: |
echo "::warning::No performance baseline cached from main branch yet. Regression check skipped. Baseline will be saved on next main branch push."
echo "NOTE: No baseline cached from main branch yet."
echo "Benchmark results recorded but regression check skipped."
echo "Baseline will be saved on next main branch push."

# Save baseline on main branch pushes
- name: Save baseline
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
uses: actions/cache/save@v4
with:
path: target/criterion
key: criterion-baseline-main

- name: Archive benchmark results
if: always()
uses: actions/upload-artifact@v4
with:
name: bench-results
path: bench_results.txt
retention-days: 90

memory-regression:
name: RSS Memory Gate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@1.94.0
- uses: Swatinem/rust-cache@v2
- name: Install redis-tools
run: sudo apt-get install -y redis-tools
- name: Build release
run: cargo build --release --no-default-features --features runtime-tokio,jemalloc
env:
MOON_NO_URING: "1"
- name: Measure RSS after 100K keys
env:
MOON_NO_URING: "1"
KEY_COUNT: "100000"
run: |
./target/release/moon --port 6399 --shards 1 &
MOON_PID=$!
sleep 2
redis-benchmark -h 127.0.0.1 -p 6399 -t set -n "${KEY_COUNT}" -r "${KEY_COUNT}" -q
sleep 1
RSS_KB=$(awk '/VmRSS/ {print $2}' /proc/${MOON_PID}/status)
RSS_MB=$((RSS_KB / 1024))
echo "RSS after ${KEY_COUNT} keys: ${RSS_MB} MB (${RSS_KB} KB)"
BASELINE_MB=150
if [ "${RSS_MB}" -gt "${BASELINE_MB}" ]; then
echo "FAILED: RSS ${RSS_MB} MB exceeds baseline ${BASELINE_MB} MB"
kill ${MOON_PID} 2>/dev/null || true
exit 1
fi
echo "PASSED: RSS ${RSS_MB} MB within baseline ${BASELINE_MB} MB"
kill ${MOON_PID} 2>/dev/null || true
35 changes: 35 additions & 0 deletions .github/workflows/changelog-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CHANGELOG Gate

on:
pull_request:
branches: [main]

jobs:
changelog-check:
name: Require CHANGELOG update
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Check for CHANGELOG changes
env:
PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Skip if 'skip-changelog' label is present
if echo "${PR_LABELS}" | grep -qi 'skip-changelog'; then
echo "skip-changelog label found -- skipping CHANGELOG check"
exit 0
fi

# Check if CHANGELOG.md was modified
if git diff --name-only "${BASE_SHA}...${HEAD_SHA}" | grep -q '^CHANGELOG.md$'; then
echo "CHANGELOG.md updated -- gate passed"
else
echo "ERROR: CHANGELOG.md was not updated in this PR."
echo "Either update CHANGELOG.md or add the 'skip-changelog' label."
exit 1
fi
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,29 @@ jobs:
- name: Audit unwrap/expect ratchet
run: bash scripts/audit-unwrap.sh

changelog:
name: CHANGELOG check
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check CHANGELOG.md touched or skip-changelog label present
env:
PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }}
run: |
if echo "$PR_LABELS" | grep -q 'skip-changelog'; then
echo "skip-changelog label found — skipping check"
exit 0
fi
if git diff origin/main...HEAD --name-only | grep -q CHANGELOG.md; then
echo "CHANGELOG.md updated"
else
echo "::error::CHANGELOG.md not updated under [Unreleased]. Add a changelog entry or apply the 'skip-changelog' label."
exit 1
fi

msrv:
name: MSRV (1.94)
runs-on: ubuntu-latest
Expand Down
Loading
Loading