Skip to content

Commit 4fc981e

Browse files
committed
ci: harden Ubuntu audio-dep install against slow apt mirrors
The Ubuntu `lint + typecheck + tests` cells kept timing out at the "System deps (PortAudio + ffmpeg)" step and getting cancelled before the tests ran, which bounced this PR out of the merge queue. Root cause: a plain `apt-get install ffmpeg` pulls a ~100-package / ~94 MB dependency closure, and against a degraded Azure Ubuntu mirror that download overran the job's 15-min timeout. Windows was unaffected (it installs only ffmpeg, in under a minute). Factor the three identical Ubuntu installs into scripts/ci_install_audio_deps.sh that (1) passes --no-install-recommends to drop the optional codec/VA-API/SDL recommends that balloon the payload, and (2) wraps each apt call in a bounded `timeout` + retry so a stalled mirror connection is killed and retried instead of wedging the whole job. Bump the two Ubuntu test jobs from 15 to 20 minutes (matching the Windows job) to give the retry path headroom. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AFrwHX8EdECmkNsU8LqJNf
1 parent c939202 commit 4fc981e

2 files changed

Lines changed: 41 additions & 5 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
check:
2727
name: lint + typecheck + tests (py${{ matrix.python-version }})
2828
runs-on: ubuntu-latest
29-
timeout-minutes: 15
29+
timeout-minutes: 20
3030
# Test both ends of the supported range: 3.12 is the floor (requires-python),
3131
# 3.13 is what the Homebrew formula ships. fail-fast off so one version's
3232
# failure doesn't mask the other's.
@@ -49,8 +49,9 @@ jobs:
4949

5050
# PortAudio backs sounddevice; ffmpeg decodes non-WAV/URL audio (the `--sample`
5151
# stream tests build a FileSource for the hosted sample, which needs ffmpeg).
52+
# Slow-mirror resilience (bounded retry + trimmed payload) lives in the script.
5253
- name: System deps (PortAudio + ffmpeg)
53-
run: sudo apt-get update && sudo apt-get install -y libportaudio2 ffmpeg
54+
run: ./scripts/ci_install_audio_deps.sh
5455

5556
# check.sh lints Markdown and template JS/CSS via Node CLIs; versions are
5657
# pinned in scripts/gate_tool_pins.sh (shared with the web session-start
@@ -245,7 +246,7 @@ jobs:
245246
pre-commit:
246247
name: pre-commit
247248
runs-on: ubuntu-latest
248-
timeout-minutes: 15
249+
timeout-minutes: 20
249250
steps:
250251
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
251252
with:
@@ -257,7 +258,7 @@ jobs:
257258

258259
# PortAudio backs sounddevice; ffmpeg decodes the `--sample` stream source.
259260
- name: System deps (PortAudio + ffmpeg)
260-
run: sudo apt-get update && sudo apt-get install -y libportaudio2 ffmpeg
261+
run: ./scripts/ci_install_audio_deps.sh
261262

262263
# The local pytest hook runs `uv run --frozen python -m pytest`, so the tests
263264
# resolve the LOCKED dependency versions (uv.lock) rather than the newest
@@ -341,7 +342,7 @@ jobs:
341342
# PortAudio + ffmpeg so `assembly --help` (which imports the full command
342343
# tree) loads cleanly; also lets install.sh's dep check find them present.
343344
- name: System deps (PortAudio + ffmpeg)
344-
run: sudo apt-get update && sudo apt-get install -y libportaudio2 ffmpeg
345+
run: ./scripts/ci_install_audio_deps.sh
345346

346347
- name: Run install.sh (editable, from this checkout)
347348
run: ./install.sh --install-method git

scripts/ci_install_audio_deps.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env bash
2+
# CI-only helper: install the Linux system audio deps the suite needs — libportaudio2
3+
# (sounddevice's PortAudio backend) and ffmpeg (decodes non-WAV/URL audio for the
4+
# `--sample` stream tests). Three Ubuntu jobs in .github/workflows/ci.yml install the
5+
# identical pair, so the slow-mirror resilience below lives in one place.
6+
#
7+
# A plain `apt-get install ffmpeg` pulls a ~100-package / ~94 MB dependency closure, and
8+
# against a degraded Azure Ubuntu mirror that download has repeatedly overrun the job's
9+
# timeout — the step hung mid-download and was cancelled before the tests ran, bouncing
10+
# the PR out of the merge queue. Two mitigations, mirroring the Windows ffmpeg step's
11+
# bounded-retry philosophy:
12+
# * --no-install-recommends drops the optional VA-API/VDPAU/SDL/pocketsphinx recommends
13+
# that balloon the download; the ffmpeg binary and the libs the tests load remain.
14+
# * each apt call is wrapped in `timeout` (run under sudo so the killer is root and can
15+
# actually reap apt) and retried, so a connection that stalls on a bad mirror edge is
16+
# killed and retried instead of wedging the whole job; apt's own Acquire::Retries
17+
# handles transient per-file failures within an attempt.
18+
set -euo pipefail
19+
20+
# Run one bounded apt-get attempt, retrying a stalled/failed call a few times.
21+
apt_retry() {
22+
local attempt
23+
for attempt in 1 2 3; do
24+
if sudo timeout --kill-after=10s 120s apt-get "$@"; then
25+
return 0
26+
fi
27+
echo "::warning::apt-get $* failed or stalled (attempt ${attempt}/3); retrying" >&2
28+
sleep "$((attempt * 5))"
29+
done
30+
echo "::error::apt-get $* failed after 3 attempts" >&2
31+
return 1
32+
}
33+
34+
apt_retry update -o Acquire::Retries=3
35+
apt_retry install -y --no-install-recommends -o Acquire::Retries=3 libportaudio2 ffmpeg

0 commit comments

Comments
 (0)