RFC-0056: CRCR Support for Nightly & Periodic CI#98
Conversation
Proposes extending CRCR to support scheduled (nightly/periodic) CI dispatches for downstream repositories. Presents two options — EventBridge cron vs. upstream GitHub Actions workflow — with detailed tradeoffs, implementation effort, and open questions for WG discussion.
| 1. Fetch pytorch/pytorch main HEAD SHA via GitHub API | ||
| 2. Build synthetic client_payload: | ||
| - event_type: "nightly" (or "periodic") | ||
| - delivery_id: "nightly-{date}-{uuid}" |
There was a problem hiding this comment.
Suggestion: use the pytorch/pytorch main HEAD commit SHA as the dispatch/correlation ID instead of a random uuid — and avoid any trigger from pytorch/pytorch.
Option 2 already fetches the main HEAD SHA here (step 1). That fetch is a pull via the GitHub API on the relay's own EventBridge schedule — it needs no workflow_dispatch/repository_dispatch/webhook emitted by pytorch/pytorch. So the relay never depends on an event from torch; it just reads GET /repos/pytorch/pytorch/commits/main. That's a strong reason to prefer Option 2 over Option 1 (Option 1's whole premise is torch emitting the event).
Given the SHA is in hand, make it the ID rather than nightly-{date}-{uuid}:
- Meaningful & correlatable — the ID is the tested commit, so HUD (and humans) can map a nightly run straight to
github.com/pytorch/pytorch/commit/<sha>. - No torch coupling — derived entirely on the relay side.
Uniqueness for the Redis state machine (DISPATCHED → IN_PROGRESS → COMPLETED): a bare SHA can collide if main hasn't advanced between two scheduled runs, or on a manual re-trigger. Two clean options:
- SHA-keyed + idempotent (recommended): key on the bare SHA and skip re-dispatch if a
DISPATCHED/COMPLETEDrecord already exists for it. Bonus — you don't re-run nightlies whenmaindidn't move. - Composite if you want exactly one nightly per calendar day regardless of
mainmovement:nightly-{sha}-{YYYYMMDD}(or-{run_id}). Keeps the SHA as the correlation key while guaranteeing a fresh state key per run.
HUD grouping (see the "HUD Changes" note near the end): this also lets you avoid the pr_number = 0 sentinel, which collapses every nightly into one bucket. Carry the SHA (already in payload.head_sha) and group non-PR runs by SHA — each nightly stays distinguishable and links to its commit. pr_number = 0 throws away that per-commit granularity.
Net design: EventBridge cron → relay reads main HEAD SHA → delivery_id = SHA (idempotent) → HUD correlates by commit — no event from pytorch/pytorch anywhere in the path.
There was a problem hiding this comment.
Sure @atalman
Also noting the differences in terms of changes between the option 1 and option 2 for clarity
Option A: EventBridge → Lambda
- Requires provisioning new AWS resources (EventBridge rules, targets, Lambda permissions, CloudWatch alarms) via change in Terraform.
- Adds a new Lambda entry point and a GitHub API dependency to fetch the HEAD SHA.
- Add Redis idempotency logic to avoid duplicate dispatches.
- Schedule changes require a Terraform deployment.
Option B: Reuse Existing Events from pytorch/pytorch workflow
- Adds a periodic trigger workflow in pytorch/pytorch
- Adds the event types in the lambda.
- Nightly uses the existing nightly branch push that already generates a webhook daily.
- The Lambda maps the ref name to a dispatch type; the SHA, delivery ID, and signature verification are all used from the current workflow.
There was a problem hiding this comment.
Also added more in-depth detail in https://docs.google.com/document/d/1VQLi45b08x_fd9_ndACtp805EThyBKajbHCO_YtGygM/edit?tab=t.0
Per @atalman's review feedback — the main HEAD SHA is already fetched, so use it as the dispatch/correlation ID. This makes the ID meaningful and lets HUD correlate nightly runs directly to the tested commit.
|
Following up on the trigger discussion — I'd like to put a third option on the table that I think fits the nightly/periodic use case better than either Option A (EventBridge cron) or Option B (reuse existing events), because it removes the scheduled trigger from the critical path entirely. Option C: Authenticated self-reportInstead of a central scheduler dispatching to downstream repos, let each downstream repo drive its own schedule and report results back. The relay stops being a trigger and becomes a validating ingest endpoint. This drops the "callback requires a prior Why this is attractive
Two requirements to make it safe
Explicit non-goal: missing-run detectionUnlike central dispatch, the relay never "expects" N callbacks, so it cannot tell "a repo's cron silently broke" from "a repo isn't participating." That's fine by design here — we only care about the signals that arrive; absence of a signal is not an error condition. This is what lets us drop all the completeness/liveness bookkeeping. On SHA alignmentIf we want rows from different backends to line up for side-by-side comparison, downstreams should pin the same stable daily ref ( NetThis keeps the SHA-as-correlation-ID improvement already applied in this PR, and it satisfies "nightly/periodic must not require a workflow to be initiated near |
Adds Option C proposed by @atalman: downstream repos self-schedule via their own crons and report results back through OIDC-validated callbacks. Includes pros/cons analysis, implementation effort estimate, updated comparison table, and open questions around state machine divergence, trust model, and missing-run detection.
Remove Option 1 (upstream cron workflow) and Option 2 (EventBridge) sections. Present only the authenticated self-report approach proposed by @atalman, where downstream repos self-schedule nightly/periodic CI and report results via OIDC-validated callbacks with SHA-keyed upserts.
Keep only the design structure and implementation details. Replace open questions/drawbacks/alternatives with a concrete file changes table showing exactly what needs to be modified.
Briefly document the two alternatives (EventBridge cron and upstream workflow) that were evaluated before settling on the authenticated self-report design, with reasons they were set aside.
Nightly runs fetch HEAD from pytorch/pytorch nightly branch (updated daily by trigger_nightly_core.yml). Periodic runs use main or viable/strict. dispatch_id is the commit SHA per @atalman's suggestion. Includes SHA source table, example downstream workflow, and updated flow diagram.
No in_progress state — downstream workflows report the final result in one callback. No Redis state tracking, no zombie sweeper needed. Adds comparison table showing PR/push vs nightly/periodic callback models.
Document the manual replay procedure via workflow_dispatch. Callbacks are idempotent (SHA-based delivery_id + upsert), so re-running is safe. Automated detection deferred to WG.
## Summary Phase 1 of the CRCR nightly/periodic self-report implementation ([RFC 98](pytorch/rfcs#98)). Adds a new code path in the callback Lambda for `nightly` and `periodic` event types. Unlike PR/push callbacks which require a `DISPATCHED` record in Redis and follow a two-step state machine (`in_progress` → `completed`), nightly/periodic callbacks use a **single-callback model**: - Downstream repo self-triggers via cron - Runs CI against a `pytorch/pytorch` SHA (from `nightly` branch or `main`) - Reports the final result in **one callback** — no `in_progress` step **What's different from PR/push:** - No Redis writes, no state machine, no zombie tracking - Status must be `completed` (rejects `in_progress`) - No upstream check runs (nightly results are informational only) - Timing metrics (queue_time, execution_time) are `null` — no dispatch record to measure against **Changes:** | File | Change | |------|--------| | `callback/callback_handler.py` | New `_handle_nightly_callback()` + routing in `handle()` | | `tests/test_callback_handler.py` | 8 new tests covering the nightly path | **Remaining phases:** - Phase 2: Update callback action YAML with `delivery-id` / `event-type` inputs - Phase 3: Downstream cron workflow in `TorchedHat/pytorch-redhat-ci` - Phase 4: ClickHouse query for nightly results - Phase 5-6: HUD display ## Test plan - [x] 8 unit tests: forward to HUD, skip Redis, no timing metrics, periodic variant, reject `in_progress`, allowlist gating, rate limiting, missing `delivery_id` - [ ] CI passes on this PR
…e 2) (#8303) ## Summary Phase 2 of the CRCR nightly/periodic self-report implementation ([RFC 98](pytorch/rfcs#98)). Extends the callback action (`.github/actions/cross-repo-ci-relay-callback/action.yml`) to support **self-report mode** for nightly/periodic workflows. Downstream repos that self-trigger via cron (no upstream `repository_dispatch`) can now report results by setting two new inputs: - **`delivery-id`**: The upstream `pytorch/pytorch` commit SHA that was tested — becomes the correlation key on the HUD - **`event-type`**: `"nightly"` or `"periodic"` When both are set, the action constructs the payload from scratch (no `client_payload` needed). Existing PR/push behavior is completely unchanged. **Validation:** - `event-type` must be `"nightly"` or `"periodic"` - `status` must be `"completed"` (single-callback model, no `in_progress` step) **Example downstream usage:** ```yaml - name: Report nightly results to CRCR if: always() uses: pytorch/test-infra/.github/actions/cross-repo-ci-relay-callback@main with: status: completed conclusion: ${{ job.status }} delivery-id: ${{ steps.sha.outputs.sha }} event-type: nightly ``` **Depends on:** Phase 1 (#8302) — callback Lambda handler for nightly/periodic ## Test plan - [ ] CI passes (actionlint) - [ ] End-to-end test with Phase 3 downstream workflow
…8304) ## Summary Phase 1.2 of the CRCR nightly/periodic self-report implementation ([RFC 98](pytorch/rfcs#98)). Adds `utils/sha_validator.py` — validates that a self-reported commit SHA exists on `pytorch/pytorch` via the GitHub API before accepting nightly/periodic callback results. **Key features:** - `validate_sha(upstream_repo, sha)` → `True` if SHA exists, `False` on 404, raises on other errors - Module-level TTL cache (1 hour) avoids redundant API calls when multiple downstream repos report against the same nightly SHA - Expired entries are evicted lazily on each call **Depends on:** Phase 1 (#8302) — will be called from `_handle_nightly_callback()` **Changes:** | File | Change | |------|--------| | `utils/sha_validator.py` | New module: SHA validation with TTL cache | | `tests/test_sha_validator.py` | 7 tests: valid/invalid SHA, cache hit/miss, TTL expiry, error propagation | ## Test plan - [x] 7 unit tests covering all paths - [ ] CI passes
Summary
Proposes extending the Cross-Repository CI Relay (CRCR) to support nightly and periodic CI for downstream repositories using an authenticated self-report model.
Currently, CRCR only dispatches on
pull_requestandpushevents. Nightly/periodic runs have no upstream trigger — the state machine rejects callbacks without a priorDISPATCHEDrecord. This RFC proposes a simpler path: downstream repos self-schedule via cron, fetch the target SHA, run CI, and report results directly to the relay in a single callback (noin_progressstate, no Redis, no state machine).Nightly Flow
The diagram below illustrates the nightly CI flow. Periodic CI follows the same pattern but fetches the SHA from
mainorviable/strictinstead of thenightlybranch. This will ensure that the results are aligned with upstream nightly results on HUD page.flowchart TD A["⏰ Downstream cron schedule<br/>(e.g., daily 02:00 UTC)"] --> B["Fetch HEAD SHA from<br/>pytorch/pytorch nightly branch"] B --> C["Build & test PyTorch<br/>at that SHA"] C --> D["Single callback to relay<br/>dispatch_id = SHA<br/>event_type = nightly<br/>conclusion = success/failure"] D --> E{"Relay validates"} E -->|"OIDC token → repo on allowlist"| F["✅ Valid"] E -->|"SHA exists on pytorch/pytorch"| F F --> G["Direct upsert to DynamoDB<br/>(no Redis, no state machine)"] G --> H["DynamoDB → ClickHouse"] H --> I["📊 HUD display<br/>hud.pytorch.org/crcr"]Callback model comparison
DISPATCHED → IN_PROGRESS → COMPLETEDin_progressthencompletedcompletedonlySHA sources
nightlynightlytrigger_nightly_core.yml)periodicmainorviable/strictThe
dispatch_idis the commit SHA itself — idempotent, correlatable, and maps directly togithub.com/pytorch/pytorch/commit/<sha>on HUD.Replay & Recovery
Nightly/periodic callbacks are idempotent by design: the
delivery_idis the upstream commit SHA, and the callback upserts into DynamoDB, so re-running the same workflow for the same SHA is safe and produces no duplicates.Manual replay: Navigate to the downstream repo's Actions tab → select the nightly workflow → click "Run workflow" (
workflow_dispatch). The workflow fetches the currentnightlybranch HEAD SHA, runs CI, and reports results via the callback action — identical to a cron-triggered run.Automated missed-nightly detection (self-healing re-triggers) may be considered in a future iteration based on WG feedback.
Implementation PRs
Related RFCs
Status
Draft — for CRCR Working Group discussion.