Skip to content

A preview is not started, or not left, for a pull request that has closed (#111) - #192

Merged
Devski merged 1 commit into
mainfrom
claude/111-preview-race
Sep 12, 2026
Merged

A preview is not started, or not left, for a pull request that has closed (#111)#192
Devski merged 1 commit into
mainfrom
claude/111-preview-race

Conversation

@Devski

@Devski Devski commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #111. A preview that comes up
after its pull request has closed stays until someone removes it by hand: the cleanup
(preview-cleanup.yml) runs on closed, and if the CI run's preview job is still on its way
it runs before there is anything to remove. Two such orphans fill the two-preview cap and block
every later pull request. Found 09.09.2026 — pr-77 up for eight hours after its merge.

The preview job now asks GitHub whether its pull request is still open twice:

  • Before starting anything. Closed → nothing is shipped, nothing started, and the run says
    why.
  • Again once the preview is up. Closed by now → the job takes the preview down itself, since
    the cleanup has already been and gone. Closing after this point is safe: the cleanup then runs
    after the preview exists.

Every interleaving of a close with the start is covered by the second read, including a cleanup
that removed part of a preview mid-start: preview-down.sh is safe to run for anything, and
twice.

What had changed since the issue was filed

The gate on main (#61, 12.09.2026) makes a merge wait for e2e-full, which starts with the
preview job and runs about four minutes to its forty seconds — so a merge had in practice
stopped winning this race
. What had not: closing a pull request without merging (no checks
needed), a slow start (the database copy since #113) outlasting the tests, and a re-run of the
preview job on a closed pull request.

Also from review

  • The second read runs even if the run was cancelled or timed out mid-start (always(), not
    !cancelled()). By the health wait at the end of preview-up.sh the container is already
    running and the script's trap does not remove it — the same orphan. A run cancelled by a newer
    push reads open and does nothing.
  • A failed read after the start warns instead of passing silently. A failed read counts as
    open, so previews keep working when the API hiccups — but after the start that is exactly where
    a missed orphan would hide, so it says so, with the command to remove it by hand.
  • Re-runs of runs from before this merge do not get the check: a re-run reads the workflow at
    its own commit. The comment says so rather than claiming otherwise.

The rest of #111

The issue's comments found a second kind of orphan: rows in dev's database naming prefixes of
previews that no longer exist. #113 ended that class — a preview now has its own database, and
its rows go with it. What stays behind is the objects under pr-<n>/ in the bucket, which belong
to #34 with a warning that must not be lost
when this issue closes: 735 of dev's rows still name objects under dead preview prefixes, so
that sweep has to delete by row, not by prefix. docs/dev-environment.md pointed at #111 for
that; it now points at #34, and the warning goes onto #34 itself.

Still possible, all narrow and older than this change

  • A run cancelled or timed out mid-start whose script keeps running on the instance — killing
    the ssh client does not stop it until its next write — can create the container after the
    second read has already removed everything. Closing that needs a lock on the instance around
    start and teardown.
  • A newer push cancelling a run mid-start, then a close, with the orphaned script's docker run
    landing in the sub-second gap between the cleanup's docker rm and its database drop.
  • scp of the preview scripts rewriting a file another pull request's script is executing.

Test plan

  • The workflow parses (PyYAML), the preview job's steps are in the intended order, and
    permissions gained only pull-requests: read
  • Both new steps' scripts, extracted from the YAML and run as Actions runs them
    (under -eo pipefail, stricter than the bash -e Actions uses for these steps) with stand-in gh and ssh:
    before the start — open → start, closed → skip with a notice, API failing → start;
    after the start — open → nothing, closed → preview-down.sh for this pull request,
    API failing → a warning, the step still green
  • Only the preview job changed (deploy-dev has the same step names; every edit was scoped)
  • ci.yml, tasks/plan.md, docs/dev-environment.md prettier-clean; pnpm check
  • This pull request's own preview came up through the new steps: pr-192 running and healthy
    on the instance, and the job emitted no annotation — both reads said open and did nothing

🤖 Generated with Claude Code

…osed (#111)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Devski
Devski merged commit c1a49a4 into main Sep 12, 2026
7 checks passed
@Devski
Devski deleted the claude/111-preview-race branch September 12, 2026 21:04
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.

Preview cleanup loses the race with a CI run still in flight; the orphan blocks the two-preview cap (#31)

1 participant