Skip to content

ci: stop the lint job's apt step hanging for six minutes - #123

Merged
widgetii merged 1 commit into
masterfrom
lint-no-apt-hang
Aug 18, 2026
Merged

ci: stop the lint job's apt step hanging for six minutes#123
widgetii merged 1 commit into
masterfrom
lint-no-apt-hang

Conversation

@widgetii

Copy link
Copy Markdown
Member

Follow-up to #122.

The unconditional apt-get update I added there to satisfy the PyYAML review finding was fine on the PR runs (~5s) and then sat for six minutes on the first master push, still in progress when I cancelled it (run 32156242103). Nothing was wrong with the tree — apt was just slow.

That's a bad trade for this job specifically. Its argument for existing, and for carrying a push trigger at all, is that it answers in seconds; I made it depend on a network fetch it doesn't normally need. ubuntu-latest ships PyYAML.

Change

Import first, install only if that fails. The dependency is still handled rather than assumed — which was the point of the finding — but a working runner pays nothing for it.

if python3 -c 'import yaml' 2>/dev/null; then
  echo "PyYAML already present; nothing to install."
else
  echo "PyYAML missing from the runner image; installing."
  sudo apt-get update -qq
  sudo apt-get install -y -qq python3-yaml
fi

if rather than python3 -c 'import yaml' && exit 0: under bash -e the latter fails the step on precisely the branch where the install needs to run. Both paths verified under -e, the missing case simulated by shadowing the module on PYTHONPATH.

Plus timeout-minutes: 10. The default is six hours, which is how a step that hangs rather than fails occupies a runner and tells nobody.

Notes

🤖 Generated with Claude Code

The unconditional `apt-get update` added to satisfy review on #122 was
fine on the PR runs (~5s) and then sat for six minutes on the first
master push, still in progress when it was cancelled. Nothing was wrong
with the tree; apt was just slow.

That is a bad trade for this job in particular. Its argument for
existing -- and for carrying a push trigger at all -- is that it answers
in seconds, and it was made to depend on a network fetch it does not
normally need. ubuntu-latest ships PyYAML.

So import first and install only if that fails. The dependency is still
handled rather than assumed, which was the point of the review finding,
but a working runner pays nothing for it. `if` rather than
`python3 -c 'import yaml' && exit 0`, because under `bash -e` the latter
fails the step on the branch where the import fails -- exactly when the
install needs to run. Both paths checked under -e.

Also timeout-minutes: 10. The default is six hours, which is how a step
that hangs rather than fails occupies a runner and tells nobody.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Finding overflow, which tucks the rest behind 'View more'

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

CI: avoid slow apt updates in lint job by installing PyYAML only when missing

⚙️ Configuration changes 🕐 Less than 10 minutes

Grey Divider

AI Description

• Add a 10-minute timeout to keep lint runs from hanging indefinitely on runners.
• Check for PyYAML via import first; fall back to apt install only when missing.
• Preserve dependency handling while keeping the common path network-free and fast.
Diagram

graph TD
  A["GitHub Actions: lint job"] --> B["Runner: ubuntu-latest"] --> C["Step: Ensure PyYAML"] --> D{"import yaml works?"}
  D -->|"yes"| E["Run linter"]
  D -->|"no"| F["apt-get update + install python3-yaml"] --> E
  subgraph Legend
    direction LR
    _job["Job/Step"] ~~~ _dec{"Decision"} ~~~ _net["Network action"]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Always pip install in a venv (or pipx) instead of apt
  • ➕ Avoids dependence on Ubuntu package naming/versioning
  • ➕ More consistent across runner images
  • ➖ Still requires network on every run unless cached
  • ➖ Extra complexity (venv creation) and still needs to handle PEP 668 constraints correctly
2. Pre-bake dependency into a custom container image for lint
  • ➕ No apt/pip at runtime; fastest and most deterministic
  • ➕ Avoids transient apt slowness entirely
  • ➖ Adds image maintenance/publishing overhead
  • ➖ Harder to iterate for a lightweight lint job
3. Use an actions/cache strategy for apt lists/packages
  • ➕ Can reduce repeated apt update/install time across runs
  • ➕ Keeps using OS packages (apt) under PEP 668
  • ➖ Caching apt reliably is tricky and can be brittle
  • ➖ Does not fully eliminate first-run network latency

Recommendation: Keep the PR’s conditional import-then-install approach: it preserves explicit dependency handling while ensuring the common case stays network-free and fast (which matches the lint job’s intent). The added job-level timeout is a pragmatic guardrail against future transient hangs.

Files changed (1) +19 / -9

Other (1) +19 / -9
lint.ymlAdd lint job timeout and conditional PyYAML apt fallback +19/-9

Add lint job timeout and conditional PyYAML apt fallback

• Adds a 10-minute timeout to the lint job to prevent long hangs. Replaces an unconditional apt update/install with a Bash check that imports PyYAML first and only runs apt when the module is missing, keeping the typical path fast and offline.

.github/workflows/lint.yml

@widgetii
widgetii merged commit 6872639 into master Aug 18, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant