agoda-com / agoda-com/Local-Dev-Telemetry-Manager

Proposal: add dedicated DB performance test project + CI benchmark job

未关闭
#16 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
C#
星标
2
派生
1
PR 合并指标
30 天内没有已合并 PR

描述

## Summary
Introduce a dedicated DB performance test project (new `.csproj`, similar structure to integration tests) and CI workflow job to benchmark query performance against seeded high-cardinality data.

This provides repeatable baseline + re-measure loops for index strategy decisions across PostgreSQL and SQLite.

---

## Motivation
We need measurable evidence in CI to:
- capture baseline timings,
- validate index changes improve target endpoints,
- prevent accidental regressions.

---

## Proposal

### 1) New project
Create a new project alongside integration tests:
- `src/Agoda.DevExTelemetry.DbPerfTests/Agoda.DevExTelemetry.DbPerfTests.csproj`

Project intent:
- host app using `WebApplicationFactory`,
- seed large deterministic + randomized dataset,
- wait for seed completion signal,
- call selected API endpoints,
- record timing distributions and compare to baseline.

### 2) Data seeding approach (DI-driven)
Inject startup seeding service via test host DI that:
- writes dataset through repository layer,
- combines deterministic + randomized data,
- creates realistic cardinality across:
- project/repository/branch/platform,
- local vs CI execution environment,
- test runners,
- date windows,
- build categories + reload types,
- uses fixed random seed for reproducibility.

### 3) Readiness gate
Do **not** rely only on health startup.

Use two gates:
1. app startup health check,
2. explicit seed completion signal (test-only seed-status endpoint or in-memory completion marker exposed to test harness).

### 4) Endpoint benchmark set (initial)
- `GET /api/dashboard/build-metrics`
- `GET /api/dashboard/test-runs`
- `GET /api/dashboard/api-build-summary`
- `GET /api/dashboard/clientside-build-summary`
- `GET /api/dashboard/test-run-summary`

Run each with filter profiles matching real query shapes (date ranges + project/repo/branch/platform/env).

### 5) Engine matrix
Run tests for both:
- SQLite
- PostgreSQL

This is required because index behavior and planner behavior diverge by engine.

---

## Seed volume contract (initial targets)
- BuildMetrics: ~100k rows
- TestRuns: ~50k rows
- TestCases: ~500k rows (avg ~10/test run)
- RawPayloads: ~50k rows

Cardinality targets:
- ~200 projects
- ~120 repositories
- ~400 branches
- representative platform/environment/test-runner spread

---

## Threshold/regression strategy
### Phase 1: stabilization (non-blocking)
- Run perf workflow nightly / on-demand.
- Publish artifacts only.

### Phase 2: regression gating
- Use **relative regression checks** vs baseline (e.g., p95 must not regress >20%).
- Avoid hardcoded absolute ms thresholds on shared runners.

---

## CI placement
Start as dedicated workflow:
- `workflow_dispatch`
- nightly schedule

After variance/runtime analysis, promote selected checks to PR gating if stable and practical.

---

## Artifact format and consumption
Primary artifact: **versioned JSON schema** for machine comparison.

Minimum fields:
- endpoint
- filter profile
- engine
- sample count
- p50 / p95 / p99
- mean / stddev
- baseline delta (%)

Generate Markdown summary from JSON for human review in workflow output/PR comments.

---

## Suggested rollout plan
1. Capture baseline query timings for key endpoints.
2. Add PostgreSQL composites first (and optional partial indexes if volume justifies).
3. Add minimal SQLite composites.
4. Re-measure and keep only indexes with measurable benefit.

---

## Acceptance criteria (initial)
- New perf test `.csproj` committed and runnable locally.
- Deterministic+randomized seed generator implemented with target volume/cardinality.
- Seed completion gating implemented (separate from app startup health).
- Dedicated CI perf workflow runs SQLite + PostgreSQL matrix and uploads JSON + Markdown artifacts.
- At least one relative regression assertion per critical endpoint (after stabilization phase).
- Docs added for local execution and artifact interpretation.
---

## Additional implementation notes (important)

### A) Seeding performance strategy
Given target volume (~700k+ rows total), do not rely on naive row-by-row EF inserts.

- PostgreSQL: use bulk-friendly ingestion strategy (batched insert or COPY-style path where feasible).
- SQLite: prefer high-throughput batched inserts and consider prebuilt seeded DB artifact option for local fast loop.
- Keep repository-layer shape for realism where practical, but optimize seed path explicitly to avoid CI timeout risk.

### B) Warm-up phase before measurement
Before capturing benchmark timings:
- run warm-up calls for representative endpoint mix (time- or iteration-based),
- ensure app startup/JIT/connection pool/ORM model initialization effects are not included in measured distribution.

### C) Benchmark execution tooling
Do not reinvent stats collection.

Preferred options:
- .NET-native harness with robust distribution capture,
- or dedicated load test tool (e.g., NBomber/k6) integrated into workflow.

Whichever path is chosen must output the agreed JSON schema (p50/p95/p99/mean/stddev/delta).

### D) Future PR gating reliability
When moving from nightly to PR-gating, use same-job A/B comparison where possible:
1. run baseline (main),
2. run candidate (PR),
3. compare deltas on same runner.

This reduces false positives from noisy shared CI hardware.

### E) Index keep/remove decision criteria
Index retention is based on both sides:
- read-time improvement on target endpoints,
- write-time/ingest penalty overhead from maintaining additional indexes.

Do not keep indexes that improve read latency marginally while significantly degrading ingest throughput.

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。