Files
vercel__workflow/.github/workflows/event-log-race-repro.yml

184 lines
8.4 KiB
YAML

name: Event Log Race Repro
on:
pull_request:
branches: [main, stable]
types: [opened, reopened, synchronize, labeled]
# Every input below is passed straight through to the harness, and a blank one
# lands on the harness' own default in
# `packages/core/e2e/event-log-race-repro.test.ts` — which is the only place
# these numbers are defined. Do not reintroduce `default:` values here: a second
# copy drifts, and the copy CI uses would stop matching the one a local run gets.
#
# The defaults are sized for a per-PR regression check. To soak for a *rate*
# instead, dispatch with the historical scale: step_storm_attempts 600,
# hook_storm_attempts 600, attempts 200, concurrency 40, budget_ms 4500000 —
# and raise `timeout-minutes` below, which is sized for the default scale.
workflow_dispatch:
inputs:
step_storm_attempts:
description: 'Number of step-storm runs (racing steps vs. watchdog + poke-hook pressure)'
required: false
hook_storm_attempts:
description: 'Number of hook-storm runs (racing hook deliveries vs. watchdog — the production shape)'
required: false
attempts:
description: 'Number of hook-sleep control runs (calibration baseline, ~0.1% historical corruption rate)'
required: false
concurrency:
description: 'Number of concurrent workflow runs'
required: false
rounds:
description: 'Rounds of racing branches per storm run (longer log = more room for a divergence to surface)'
required: false
width:
description: 'Racing branches per round (each one is an independent wake source, so this is the main concurrency dial)'
required: false
watchdog_ms:
description: 'Per-branch watchdog timeout. Branches that time out emit an extra step, which is what shifts the correlation-ID sequence'
required: false
step_delay_ms:
description: 'step-storm: raced step duration. Must straddle watchdog_ms once jitter is applied'
required: false
hook_resume_stagger_ms:
description: 'hook-storm: per-index delay inside a round resume burst. width * this should exceed watchdog_ms'
required: false
poke_interval_ms:
description: 'step-storm: cadence of out-of-band resumes to the never-read poke hook'
required: false
run_timeout_ms:
description: 'Per-run timeout before classifying as stuck'
required: false
budget_ms:
description: 'Wall-clock budget for launching attempts. Must stay far enough below the job timeout to leave room for rendering the summary'
required: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/stable' }}
jobs:
event-log-race-repro:
name: Event Log Race Repro
runs-on: ubuntu-latest
# Sized for the harness' default scale: its own test timeout is
# `budget_ms + run_timeout_ms + 60s` (~17 min at the defaults), and the rest is
# checkout, build, the deployment wait, and rendering the summary. A soak
# dispatch that raises `budget_ms` has to raise this too, or the runner kills
# the job before the summary is written.
timeout-minutes: 25
if: ${{ github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'event-log-race-repro') }}
permissions:
contents: read
deployments: read
statuses: read
id-token: write
issues: write
pull-requests: write
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
WORKFLOW_PUBLIC_MANIFEST: '1'
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup environment
uses: ./.github/actions/setup-workflow-dev
with:
build-packages: 'false'
- name: Build CLI
run: pnpm turbo run build --filter='@workflow/cli'
- name: Wait for Vercel deployment
id: waitForDeployment
uses: vercel/wait-for-deployment-action@0e2b0c5c5cce31f1648108aeec56467187aca037
with:
project-slug: example-nextjs-workflow-turbopack
timeout: 1000
check-interval: 15
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
- name: Run event log race repro
id: repro
continue-on-error: true
run: pnpm run test:e2e:event-log-race-repro --reporter=default
env:
NODE_OPTIONS: "--enable-source-maps"
DEPLOYMENT_URL: ${{ steps.waitForDeployment.outputs.deployment-url }}
VERCEL_DEPLOYMENT_ID: ${{ steps.waitForDeployment.outputs.deployment-id }}
APP_NAME: nextjs-turbopack
WORKFLOW_VERCEL_ENV: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
WORKFLOW_VERCEL_AUTH_TOKEN: ${{ secrets.VERCEL_LABS_TOKEN }}
WORKFLOW_VERCEL_TEAM: "team_nO2mCG4W8IxPIeKoSsqwAxxB"
WORKFLOW_VERCEL_PROJECT: "prj_yjkM7UdHliv8bfxZ1sMJQf1pMpdi"
WORKFLOW_VERCEL_PROJECT_SLUG: example-nextjs-workflow-turbopack
VERCEL_WORKFLOW_SERVER_URL: ${{ github.ref != 'refs/heads/main' && secrets.VERCEL_WORKFLOW_SERVER_URL || '' }}
# Deliberately unguarded pass-through: on a `pull_request` event every
# `inputs.*` is empty, and the harness reads an empty variable as unset
# and falls back to its own default. See the note on the inputs above.
EVENT_LOG_RACE_REPRO_STEP_STORM_ATTEMPTS: ${{ inputs.step_storm_attempts }}
EVENT_LOG_RACE_REPRO_HOOK_STORM_ATTEMPTS: ${{ inputs.hook_storm_attempts }}
EVENT_LOG_RACE_REPRO_ATTEMPTS: ${{ inputs.attempts }}
EVENT_LOG_RACE_REPRO_CONCURRENCY: ${{ inputs.concurrency }}
EVENT_LOG_RACE_REPRO_ROUNDS: ${{ inputs.rounds }}
EVENT_LOG_RACE_REPRO_WIDTH: ${{ inputs.width }}
EVENT_LOG_RACE_REPRO_WATCHDOG_MS: ${{ inputs.watchdog_ms }}
EVENT_LOG_RACE_REPRO_STEP_DELAY_MS: ${{ inputs.step_delay_ms }}
EVENT_LOG_RACE_REPRO_HOOK_RESUME_STAGGER_MS: ${{ inputs.hook_resume_stagger_ms }}
EVENT_LOG_RACE_REPRO_POKE_INTERVAL_MS: ${{ inputs.poke_interval_ms }}
EVENT_LOG_RACE_REPRO_RUN_TIMEOUT_MS: ${{ inputs.run_timeout_ms }}
EVENT_LOG_RACE_REPRO_BUDGET_MS: ${{ inputs.budget_ms }}
- name: Fetch previous repro comment
if: always() && github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api \
"repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments?per_page=100" \
--jq '[.[] | select(.body | contains("<!-- event-log-race-repro-results -->"))][-1].body // ""' \
> event-log-race-repro-previous-comment.md
- name: Render repro summary
if: always()
run: |
previous_comment_args=()
if [ -f event-log-race-repro-previous-comment.md ]; then
previous_comment_args=(--previous-comment event-log-race-repro-previous-comment.md)
fi
node .github/scripts/render-event-log-race-repro-results.js \
event-log-race-repro-results.json \
--run-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
--run-attempt "${{ github.run_attempt }}" \
--timestamp "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
"${previous_comment_args[@]}" \
| tee event-log-race-repro-summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Update PR comment
if: always() && github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
header: event-log-race-repro-results
path: event-log-race-repro-summary.md
- name: Upload repro results
if: always()
uses: actions/upload-artifact@v4
with:
name: event-log-race-repro-results
path: |
event-log-race-repro-results.json
event-log-race-repro-summary.md
retention-days: 7
if-no-files-found: ignore
- name: Fail on corrupted, failed, or stuck runs
if: always()
run: node .github/scripts/render-event-log-race-repro-results.js event-log-race-repro-results.json --check