Skip to content

run_smoke: cap each entry and kill its process group on expiry - #146

Merged
Jammy2211 merged 1 commit into
mainfrom
claude/backport-per-script-timeout-r3w1sv
Aug 23, 2026
Merged

run_smoke: cap each entry and kill its process group on expiry#146
Jammy2211 merged 1 commit into
mainfrom
claude/backport-per-script-timeout-r3w1sv

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Leg A of the per-script timeout backport. Depends on PyAutoHands#257, which adds the kill_group helper this imports — merge that first (the imports are guarded, so an older Hands falls back rather than breaking the gate).

The defect

Both legs of this runner ran uncapped: run_script and execute_notebook each called subprocess.run(capture_output=True) with no timeout= at all. When an entry leaves a grandchild holding the inherited stdout pipe, the parent blocks on that pipe forever — even though the entry's own work finished and the direct child exited. The gate then sits until the 6-hour GitHub Actions ceiling, reporting nothing since the last completed entry. That is autolens_workspace_test#196; this runner had the same shape in two places.

This variant was not previously identified as exposed — the earlier survey framed the missing cap as a workspace_test-tier divergence. It is six repos wide, and these three are the gates on the public workspaces.

Reproduced, against this exact file

With BUILD_SCRIPT_TIMEOUT=4:

Leg Before After
script printed ::group::script: hangs.py and nothing more; still hung when killed at 30s [TIMEOUT (4s)] hangs.py — 4.0s, exit 1, zero survivors
notebook uncapped jupyter nbconvert --execute [TIMEOUT (4s)], group reaped including the grandchild the fake jupyter forked

The jupyter-not-found path still reports exit 127 with its own message, unchanged.

Notes on the notebook leg

A notebook timeout deliberately skips the regenerate-and-retry path. A timeout is not a stale notebook, and retrying would burn a second full cap to reach the same answer — doubling the slowest entry's cost.

Also

Drops the vestigial _BUILD_DIR intermediate in autogalaxy_workspace (the sibling PR), the last real drift between the three copies of this runner. All three are byte-identical again after this series.


Generated by Claude Code

Both legs of this runner ran uncapped: run_script and execute_notebook each
called subprocess.run(capture_output=True) with no timeout at all. When an
entry leaves a grandchild holding the inherited stdout pipe, the parent
blocks on that pipe forever — even though the entry's own work finished and
the direct child exited. The gate then sits until the 6-hour GitHub Actions
ceiling, reporting nothing since the last completed entry. That is
autolens_workspace_test#196; this runner had the same shape in two places.

Reproduced against this exact file, then re-run after the change:

  script leg   — a script spawning a grandchild and exiting: old runner
                 printed "::group::script: hangs.py" and nothing more, still
                 hung when killed at 30s with BUILD_SCRIPT_TIMEOUT=4 set.
                 New: "[TIMEOUT (4s)] hangs.py — 4.0s", exit 1, no survivors.
  notebook leg — a jupyter that hangs and spawns a grandchild: new runner
                 reports TIMEOUT (4s) and reaps the group. The
                 jupyter-not-found path still reports exit 127 with its own
                 message, unchanged.

Adopts what autolens_workspace_test already runs: the cap resolved per entry
via timeout_for(env), so a profile's BUILD_SCRIPT_TIMEOUT override is read
parent-side where the kill timer lives; the child in its own session so the
whole group dies; exit 124 rather than the signal, because a timeout means
"raise the cap or SLOW-skip it" and -9 would mislabel it an ordinary failure.
timeout_for and kill_group come from PyAutoHands build_util — guarded imports
with local fallbacks, so an older Hands on PYTHONPATH cannot break the gate.

A notebook timeout deliberately skips the regenerate-and-retry path: a
timeout is not a stale notebook, and retrying would burn a second full cap to
reach the same answer.

Also drops the vestigial _BUILD_DIR intermediate in autogalaxy_workspace,
the last real drift between the three copies of this runner; all three are
now byte-identical again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTPM1RmMvSuMvJkEntAMv8
@Jammy2211
Jammy2211 merged commit 747a02d into main Aug 23, 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