Skip to content

Commit 5f99905

Browse files
authored
[CRCR] Base relay health on last 5 PR pass rates (#8454)
## Summary Changes the CRCR Relay Health card on the summary page (`hud.pytorch.org/crcr`) to evaluate health based on whether the **last 5 PR-level crcr-test runs all passed**, instead of the aggregate pass rate over the entire time window. ### Before - Health = `total_successes / total_runs` across all jobs in the time window - A high historical pass rate could mask recent regressions ### After - Health = "Healthy" only if all 5 most recent PR runs have 100% pass rate - "Degraded" if any of the last 5 PRs had a failure - Subtitle shows `X/5 recent PRs passed` for quick context ### Changes - New `crcr_health_last_prs` ClickHouse query: fetches the 5 most recent distinct PRs for `pytorch/crcr-test`, computes per-PR pass rates with expected-outcome handling (`xfail`, `xcancel`, `xtimeout`) - Updated `CrcrTestHealthCard` component to use the new per-PR health data instead of the aggregate metrics Fixes #8424 ## Test plan - Visit `/crcr` — Health card should show "Healthy" only when all 5 recent PRs passed - If any of the last 5 PRs had unexpected failures, card should show "Degraded" - Subtitle displays `X/5 recent PRs passed · pytorch/crcr-test`
1 parent 50a4098 commit 5f99905

3 files changed

Lines changed: 73 additions & 11 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"params": {
3+
"count": "UInt64"
4+
},
5+
"tests": [
6+
{
7+
"count": "5"
8+
}
9+
]
10+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
SELECT
2+
pr_number,
3+
max(started_at) AS last_run,
4+
countIf(
5+
conclusion = 'success'
6+
OR (job_name LIKE '%xfail%' AND conclusion = 'failure')
7+
OR (job_name LIKE '%xcancel%' AND conclusion = 'cancelled')
8+
OR (job_name LIKE '%xtimeout%' AND conclusion = 'timed_out')
9+
) AS successes,
10+
count() AS total,
11+
if(total > 0, successes / total, 0) AS pass_rate
12+
FROM
13+
default.crcr_workflow_job FINAL
14+
WHERE
15+
downstream_repo = 'pytorch/crcr-test'
16+
AND status = 'completed'
17+
AND pr_number > 0
18+
AND pr_number IN (
19+
SELECT pr_number
20+
FROM
21+
default.crcr_workflow_job FINAL
22+
WHERE
23+
downstream_repo = 'pytorch/crcr-test'
24+
AND status = 'completed'
25+
AND pr_number > 0
26+
GROUP BY
27+
pr_number
28+
ORDER BY
29+
max(started_at) DESC
30+
LIMIT {count: UInt64}
31+
)
32+
GROUP BY
33+
pr_number
34+
ORDER BY
35+
last_run DESC

torchci/pages/crcr/index.tsx

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ interface NightlyMetricsRow {
5555
latest_sha: string;
5656
}
5757

58+
interface HealthPrRow {
59+
pr_number: number;
60+
last_run: string;
61+
successes: number;
62+
total: number;
63+
pass_rate: number;
64+
}
65+
5866
type EventTab = "pr" | "nightly";
5967

6068
type Level = "L1" | "L2" | "L3" | "L4";
@@ -441,15 +449,15 @@ function StatCard({
441449
}
442450

443451
function CrcrTestHealthCard({
444-
metrics,
452+
healthPrs,
445453
}: {
446-
metrics: CiMetricsRow | undefined;
454+
healthPrs: HealthPrRow[] | undefined;
447455
}) {
448-
if (!metrics) return null;
449-
const pct = (metrics.pass_rate * 100).toFixed(1) + "%";
450-
const isHealthy = metrics.pass_rate >= 1.0;
451-
const borderColor = isHealthy ? "#2e7d32" : "#ed6c02";
452-
const label = isHealthy ? "Healthy" : "Degraded";
456+
if (!healthPrs || healthPrs.length === 0) return null;
457+
const allPassed = healthPrs.every((pr) => pr.pass_rate >= 1.0);
458+
const passedCount = healthPrs.filter((pr) => pr.pass_rate >= 1.0).length;
459+
const borderColor = allPassed ? "#2e7d32" : "#ed6c02";
460+
const label = allPassed ? "Healthy" : "Degraded";
453461
return (
454462
<NextLink href="/crcr/pytorch/crcr-test" passHref legacyBehavior>
455463
<Paper
@@ -474,8 +482,7 @@ function CrcrTestHealthCard({
474482
{label}
475483
</Typography>
476484
<Typography variant="caption" color="text.secondary">
477-
{pct} · {metrics.successes}/{metrics.total} jobs passed ·
478-
pytorch/crcr-test
485+
{passedCount}/{healthPrs.length} recent PRs passed · pytorch/crcr-test
479486
</Typography>
480487
</Paper>
481488
</NextLink>
@@ -507,6 +514,15 @@ export default function CrcrSummaryPage() {
507514
NightlyMetricsRow[]
508515
>(nightlyUrl, fetcherHandleError, { refreshInterval: 60_000 });
509516

517+
const healthUrl =
518+
`/api/clickhouse/crcr_health_last_prs?parameters=` +
519+
encodeURIComponent(JSON.stringify({ count: "5" }));
520+
const { data: healthPrs, error: healthError } = useSWR<HealthPrRow[]>(
521+
healthUrl,
522+
fetcherHandleError,
523+
{ refreshInterval: 60_000 }
524+
);
525+
510526
const nightlyRepoCount = nightlyData?.length ?? 0;
511527

512528
const metricsMap = useMemo(() => {
@@ -597,7 +613,7 @@ export default function CrcrSummaryPage() {
597613
}, [ciData, metricsMap, allowlist, days]);
598614

599615
const isLoading = !ciData && !ciError && !allowlist && !alError;
600-
const hasError = ciError || alError || nightlyError;
616+
const hasError = ciError || alError || nightlyError || healthError;
601617

602618
return (
603619
<>
@@ -652,6 +668,7 @@ export default function CrcrSummaryPage() {
652668
{ciError?.message ||
653669
alError?.message ||
654670
nightlyError?.message ||
671+
healthError?.message ||
655672
"Failed to load data"}
656673
</Typography>
657674
)}
@@ -661,7 +678,7 @@ export default function CrcrSummaryPage() {
661678
{stats && (
662679
<Stack spacing={2}>
663680
<Box sx={{ display: "flex", gap: 2, flexWrap: "wrap" }}>
664-
<CrcrTestHealthCard metrics={metricsMap.get(CRCR_HEALTH_REPO)} />
681+
<CrcrTestHealthCard healthPrs={healthPrs} />
665682
<StatCard
666683
label="Total Probe Runs"
667684
value={stats.totalRuns}

0 commit comments

Comments
 (0)