Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions .github/scripts/github-actions-queue/DATA_BRANCH_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ documented one-time migration. `state.json` tracks live collection, and
`backfill-state.json` tracks automatic historical collection.
The files under `migrations/` record completed one-time data cleanups.

With `DATA_BRANCH_SNAPSHOTS=true` in the source repository, each update replaces
the branch with a parentless commit. Current files retain the historical job
measurements; previous Git snapshots are not retained. The commit's
`Data-snapshot-generation` trailer orders snapshots without retaining their
parents.

`report-state.json.gz` tracks the immutable files included in the hourly
aggregates. `report-data/manifest.json` and the daily JSON files under
`report-data/` are compact derived inputs for the
Expand Down
105 changes: 102 additions & 3 deletions .github/scripts/pull-request-dashboard/WEBHOOK_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,12 @@ older worker cannot process active `backfill` or `reminders` items.
intact so receipts continue suppressing duplicates.

The execution change does not alter accepted-state or delivery formats, so this
rollback does not require releasing or promoting dashboard code. Existing
version guards still apply to any separate code rollback. Do not bypass them
or discard delivery receipts to make older code publish.
rollback does not require releasing or promoting dashboard code. If data
snapshots have been activated, keep `DATA_BRANCH_SNAPSHOTS=true` and retain
snapshot-capable code in every legacy reader and writer; returning to legacy
execution does not restore Git history. Existing version guards still apply
to any separate code rollback. Do not bypass them or discard delivery receipts
to make older code publish.

### Manual maintenance

Expand All @@ -465,3 +468,99 @@ Delivery is not exactly once. A GitHub or Slack call can succeed immediately
before worker death or receipt persistence failure. Existing comment markers,
live-state reconciliation, and durable delivery receipts suppress ordinary
duplicates, but that external-success/receipt-loss window remains.

## 7. Data branch snapshot cutover

`DATA_BRANCH_SNAPSHOTS` is a repository-level GitHub Actions variable shared by
the dashboard and Actions queue collector. Empty or `false` retains ordinary
Git history. `true` writes parentless snapshots with the complete current tree,
including historical CI records and delivery acknowledgements. Other values
fail explicitly.

Snapshot commits have a monotonically increasing `Data-snapshot-generation`
trailer. Dashboard fetches use it to reject stale snapshots, and every push
uses the exact SHA loaded before processing as its force-with-lease expectation.
A rejected dashboard update refetches and reapplies its changes. A rejected
collector push fails the job; the next run resumes from the accepted checkpoint.
Unchanged snapshots do not create commits. The first snapshot compacts a legacy
branch even when its files have not changed.

### Deployment order

1. Merge the snapshot-capable code with the variable unset. Release and promote
it through `promote-pull-request-dashboard.yml` so every stable workflow pin
loads the new reader and writer. In owned mode, verify the immutable stable
code refs used by both live and maintenance drains as well as the canary
ref. Verify the legacy queue drain, author reminder sweep, and CI collector
also run the new code. Do not rerun older workflow attempts after activation.
Snapshot activation requires this promotion even though changing execution
ownership alone does not.
2. Record the current execution mode. Pause the Netlify bridge first, then set
GitHub's `PR_DASHBOARD_EXECUTION_MODE` to `paused`, using the commands in
section 6. Keep both paused throughout compaction so webhooks remain queued
and recovery cannot start either lane. Temporarily disable
`pull-request-dashboard.yml`, `pull-request-dashboard-drain.yml`,
`pull-request-dashboard-refresh-author-nudges.yml`, and
`github-actions-queue-collector.yml`. Wait until every live and maintenance
drain, legacy writer, and collector has finished, including queued runs and
runnerless publisher jobs. Retiring a specific old run requires separate
cancellation approval. Do not take the backup while any writer remains.
Keep the stalled-run watchdog enabled; no Netlify code change is required.
3. From a dedicated maintenance clone, fetch the latest generated branches.
Record each branch's head and tree SHA, and create a verified Git bundle
backup outside this repository. Never push backup branches or tags here:
any ref to old commits keeps that history reachable to clones.
4. Set the repository variable while writers are paused:

```sh
gh variable set DATA_BRANCH_SNAPSHOTS --body true --repo open-telemetry/shared-workflows
```

5. Compact `otelbot/github-actions-queue-data` and every
`otelbot/pull-request-dashboard-state/*` and
`otelbot/pull-request-dashboard-delivery/*` branch. For each branch, use a
clean temporary worktree at its recorded head and the helper from the new
source checkout. Configure its Git author and authenticated `origin`, then:

```sh
DATA_BRANCH_SNAPSHOTS=true python3 "$SOURCE_CHECKOUT/.github/scripts/pull-request-dashboard/state_branch.py" commit-data \
--state-dir "$DATA_DIRECTORY" \
--state-branch "$BRANCH" \
--expected-sha "$RECORDED_HEAD" \
--message "Compact generated data"
```

`SOURCE_CHECKOUT` contains the promoted code, `DATA_DIRECTORY` is that
branch's temporary worktree, and `RECORDED_HEAD` is the exact backed-up SHA.
The helper snapshots the index and working tree, so verify they are clean
before invoking it. A lease failure means a writer or operator changed the
branch; stop and reconcile it rather than refreshing the lease blindly.
6. Verify every compacted remote head has no parents and its tree SHA matches
the recorded tree. Make a fresh normal clone and measure its object storage.
Other branches or tags that reference the old data can still retain history.
Reenable the disabled workflows while execution remains paused. Restore
GitHub's recorded execution mode, then deploy the bridge with that same mode
using the section 6 procedure. Confirm collection, dashboard publication,
and delivery acknowledgements continue from their existing state, and in
owned mode follow work in both lanes through completion.

### Recovery and clone size

Keep `DATA_BRANCH_SNAPSHOTS=true` after cutover. Turning it off cannot safely
restore the ancestry-based protocol; the new writer rejects a snapshot branch
when the variable is disabled. Older workflow code cannot participate in the
snapshot protocol.

If cutover fails before writers resume, keep them paused, restore the recorded
heads from the external backup with explicit leases against the compacted
heads, verify their trees, and unset `DATA_BRANCH_SNAPSHOTS` before restoring
both execution modes and starting fresh runs.
After processing resumes, restoring an old backup can discard CI checkpoints
or repeat notifications. Recover the latest accepted state instead, with a
snapshot generation higher than the current head.

Compaction removes old history from the generated branch refs, not from
existing clones. A fresh clone avoids that history once no advertised branch
or tag retains it. Existing clones also retain local refs, reflogs, and packed
objects; a fresh clone is the safest way to reclaim that space. GitHub may
retain unreachable objects and pull request refs separately.
Loading
Loading