mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
* ci: bound the ffmpeg apt fetch so a stalled mirror costs a retry, not the job Hosted runners intermittently stall on an apt mirror, and an unbounded apt-get inherits the whole job budget. The producer integration lane normally finishes in ~11 minutes against a 20 minute cap; on a stalled fetch it ran to the cap and failed. Same step, same shape, reproduces on main's tip — it is not specific to any one PR. The cost is not one red check. On the run that prompted this, four went red off that single step: the two jobs that install ffmpeg, plus a Test gate and a preview-regression gate that both fail closed when their dependency does not succeed. So a mirror stall reads as a producer defect and a preview defect. Each attempt is now bounded and retried three times, and the five workflows that installed ffmpeg share one action instead of five copies of the command. Deliberately still apt: caching the binary would strip it from the shared libraries it links against, and switching to a static build would change the ffmpeg under the producer's output comparisons. Neither belongs in a fix for a network stall. * ci: drop the stray version echo left in the player-perf ffmpeg step Converting the step to the shared action left the trailing `ffmpeg -version` line behind, and YAML folded it into the `uses:` value — so the runner looked for an action at a path with the command appended and failed all four perf shards. It parsed cleanly, which is why validating with a YAML load did not catch it: `uses: ./path\n ffmpeg -version` is a legal folded scalar. The check that does catch it asserts every local `uses:` resolves to a directory containing an action file, which is now what I ran. The action prints the version itself. * ci: bound the ffmpeg fetch at the connection, not with a wall-clock kill The first version wrapped apt in `timeout` and retried. A passing run showed why that is the wrong shape: the mirror is slow rather than hung — the install spent ~15 minutes pulling packages from azure.archive.ubuntu.com and finished successfully. Killing it at 300s discarded a download that was making progress and started over, so the retry turned a slow mirror into a slower one, and the worst case of three attempts exceeded the job's own 20 minute cap. Bound the connection instead. Acquire::Retries re-fetches the one package whose connection stalled while keeping everything already downloaded, and Acquire::http::Timeout caps how long any single connection may sit idle. That addresses the stall the original report described without punishing the slow case that is far more common.
165 lines
5.6 KiB
YAML
165 lines
5.6 KiB
YAML
name: Player perf
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
|
# External users' CI continues to emit telemetry unless they set this themselves.
|
|
env:
|
|
HYPERFRAMES_NO_TELEMETRY: "1"
|
|
|
|
on:
|
|
pull_request:
|
|
push:
|
|
branches: [main]
|
|
|
|
concurrency:
|
|
group: player-perf-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
changes:
|
|
name: Detect changes
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 2
|
|
outputs:
|
|
perf: ${{ steps.filter.outputs.perf }}
|
|
steps:
|
|
# Force git-based change detection instead of the pull_request REST API.
|
|
# The API path can fail the perf workflow on transient listFiles timeouts.
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
fetch-depth: 0
|
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
|
id: filter
|
|
with:
|
|
token: ""
|
|
filters: |
|
|
perf:
|
|
- "packages/player/**"
|
|
- "packages/core/**"
|
|
- "package.json"
|
|
- "bun.lock"
|
|
- ".github/workflows/player-perf.yml"
|
|
|
|
preflight:
|
|
name: Preflight (lint + format)
|
|
needs: changes
|
|
if: needs.changes.outputs.perf == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
- uses: ./.github/actions/preflight
|
|
|
|
perf-shards:
|
|
name: "Perf: ${{ matrix.shard }}"
|
|
needs: [changes, preflight]
|
|
if: needs.changes.outputs.perf == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
strategy:
|
|
fail-fast: true
|
|
matrix:
|
|
include:
|
|
- shard: load
|
|
scenarios: load
|
|
runs: "5"
|
|
- shard: fps
|
|
scenarios: fps
|
|
runs: "3"
|
|
- shard: scrub
|
|
scenarios: scrub
|
|
runs: "3"
|
|
- shard: drift
|
|
scenarios: drift
|
|
runs: "3"
|
|
- shard: parity
|
|
scenarios: parity
|
|
runs: "3"
|
|
steps:
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
|
|
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
|
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
with:
|
|
node-version: 22
|
|
|
|
- run: bun install --frozen-lockfile
|
|
|
|
# Player perf loads packages/player/dist/hyperframes-player.global.js
|
|
# and packages/core/dist/hyperframe.runtime.iife.js, so a full build is required.
|
|
- run: bun run build
|
|
|
|
- name: Set up Chrome (headless shell)
|
|
id: setup-chrome
|
|
uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1
|
|
with:
|
|
chrome-version: stable
|
|
|
|
# The parity scenario shells out to `ffmpeg -lavfi ssim` to score the
|
|
# live-playback frame against the sync-seek reference frame. ffmpeg is
|
|
# not on the default ubuntu-latest runner image, and a missing binary
|
|
# surfaces as ENOENT inside computeSsim() — informative, but cheaper
|
|
# to just install it here so the shard never trips on infra.
|
|
- name: Install ffmpeg (parity shard only)
|
|
if: matrix.shard == 'parity'
|
|
uses: ./.github/actions/install-ffmpeg-linux
|
|
|
|
- name: Run player perf — ${{ matrix.shard }} (measure mode)
|
|
working-directory: packages/player
|
|
env:
|
|
PUPPETEER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
|
|
run: |
|
|
bun run perf \
|
|
--mode=measure \
|
|
--scenarios=${{ matrix.scenarios }} \
|
|
--runs=${{ matrix.runs }}
|
|
|
|
- name: Upload perf results
|
|
if: always()
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
with:
|
|
name: player-perf-${{ matrix.shard }}
|
|
path: packages/player/tests/perf/results/
|
|
if-no-files-found: warn
|
|
retention-days: 30
|
|
|
|
# Summary job — matches the required check name in branch protection.
|
|
# Logs an explicit "skipped" / "passed" / "failed" line both to stdout and to
|
|
# $GITHUB_STEP_SUMMARY so a false skip is obvious in the Checks UI without
|
|
# having to dig into the changes-job logs.
|
|
player-perf:
|
|
runs-on: ubuntu-latest
|
|
needs: [changes, perf-shards]
|
|
if: always()
|
|
steps:
|
|
- name: Check results
|
|
env:
|
|
PERF_FILTER_RESULT: ${{ needs.changes.outputs.perf }}
|
|
PERF_SHARDS_RESULT: ${{ needs.perf-shards.result }}
|
|
run: |
|
|
{
|
|
echo "## Player perf gate"
|
|
echo ""
|
|
echo "- paths-filter \`perf\` matched: \`${PERF_FILTER_RESULT}\`"
|
|
echo "- perf-shards result: \`${PERF_SHARDS_RESULT}\`"
|
|
echo ""
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
if [ "${PERF_FILTER_RESULT}" != "true" ]; then
|
|
echo "::notice title=Player perf::SKIPPED — no changes under packages/player/**, packages/core/**, package.json, bun.lock, or .github/workflows/player-perf.yml. Auto-pass."
|
|
echo "**Status:** SKIPPED (no player/core changes — auto-pass)" >> "$GITHUB_STEP_SUMMARY"
|
|
exit 0
|
|
fi
|
|
|
|
if [ "${PERF_SHARDS_RESULT}" != "success" ]; then
|
|
echo "::error title=Player perf::FAILED — perf-shards result was '${PERF_SHARDS_RESULT}'. See the per-shard logs above."
|
|
echo "**Status:** FAILED (perf-shards result: \`${PERF_SHARDS_RESULT}\`)" >> "$GITHUB_STEP_SUMMARY"
|
|
exit 1
|
|
fi
|
|
|
|
echo "::notice title=Player perf::PASSED — all perf shards completed successfully."
|
|
echo "**Status:** PASSED" >> "$GITHUB_STEP_SUMMARY"
|