Skip to content

ci: bake the two smoke sites at once instead of one after the other - #470

Merged
lens0021 merged 1 commit into
mainfrom
claude/smoke-bake-at-once
Aug 19, 2026
Merged

ci: bake the two smoke sites at once instead of one after the other#470
lens0021 merged 1 commit into
mainfrom
claude/smoke-bake-at-once

Conversation

@lens0021

@lens0021 lens0021 commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #469. Review the top commit; the base merges first.

The reproducibility check bakes the docs site a second time and diffs it, and the two bakes were 209s of the smoke job's 321s. They are independent by construction, so they can run together.

The reason it pays is that a bake is mostly one process. Only the skin passes run beside each other, and even those are three on a four-core runner, so a second bake fills cores the first leaves idle rather than taking any from it.

Measured

Two containers pinned to four cores, the runner's count, on an image built from this PR's base:

wall clock
one bake alone 118s
two, one after the other 257s
two at once, four cores between them 150s
two at once, two cores each 166s

150s is what landed: no cpu flags, both bakes left to size themselves as they do today. Capping each at two cores is slower, because that also halves the concurrency of the part which does parallelise.

An earlier run of this benchmark gave the concurrent case a spurious win by capping each container at four cores on a fourteen-core host. That is eight cores between them, and not a runner at all. Discarded.

Peak combined resident memory was 1 GiB against the runner's 16, with no OOM in either log. That was the risk worth measuring: two bakes at three skin passes each is six MediaWiki boots at once.

Output is byte-identical in every configuration above, which is the check itself agreeing.

The step's own shell

Each bake writes to its own log, because two live logs interleave into neither, and both are printed afterwards in collapsed groups.

Verified that a failure still fails the step: a bake pointed at a source directory that does not exist ends it non-zero, and the success path ends it zero. Ran the step's shell verbatim, not a paraphrase of it.

The source mount is read-only now that two containers share it, so neither can alter what the other is reading. Only wikven translate writes into src, and this is not that.

Refs #461.

On the nine minutes in the issue

Worth recording, since it changes what is left to do. #461 measured 535s wall clock on #458, dominated by binary at 467s. But binary is path-filtered and does not run on a pull request that only touches PHP. On #466, which did exactly that, all 21 checks started within two seconds of each other and smoke at 317s was the longest:

317s  smoke
186s  coverage
145s  phan (master)
 52s  phpunit (REL1_46)
 43s  docker-image

So a PHP-only pull request already goes green in about five and a half minutes, and smoke is the whole of its critical path. The nine minutes belongs to image-touching pull requests, where binary is the long pole and a separate question.

This PR and #471 take smoke after the two of them from 321s to roughly 190s.

The reproducibility check bakes the docs site a second time and diffs it, and the two bakes were 209s of the smoke job's 321s. They are independent by construction, so they can run together.

The reason it pays is that a bake is mostly one process. Only the skin passes run beside each other, and even those are three on a four-core runner, so a second bake fills cores the first leaves idle rather than taking any from it.

Measured locally with two containers pinned to four cores, the runner's count, on an image built from this commit's parent:

| | wall clock |
|---|---|
| one bake alone | 118s |
| two, one after the other | 257s |
| two at once, four cores between them | 150s |
| two at once, two cores each | 166s |

150s is the shape that landed: no cpu flags, both bakes left to size themselves as they do today. Capping them at two cores each is slower, because it also halves the concurrency of the part that does parallelise.

An earlier run of the same benchmark gave two bakes at once a spurious win by capping each at four cores on a fourteen-core host, which is eight cores between them and not a runner at all.

Peak combined resident memory was 1 GiB against the runner's 16, with no OOM in either log, which was the risk worth measuring: two bakes at three skin passes each is six MediaWiki boots at once.

The source mount is read-only now that two containers share it. Only `wikven translate` writes into src, and this is not that.

Each bake writes to its own log, because two live logs interleave into neither, and both are printed in collapsed groups afterwards. Verified that the step's own shell propagates a failure: a bake pointed at a source that does not exist ends the step non-zero.

Output is byte-identical across every configuration above, which is the check itself agreeing.

Refs #461.

---
_Generated by [Claude Code](https://claude.ai/code/session_935f02d1)_

Co-authored-by: Claude <noreply@anthropic.com>
@lens0021
lens0021 force-pushed the claude/smoke-bake-at-once branch from 48cabbf to f563b87 Compare August 19, 2026 04:23
@lens0021
lens0021 merged commit 9f584ba into main Aug 19, 2026
21 checks passed
@lens0021
lens0021 deleted the claude/smoke-bake-at-once branch August 19, 2026 04:29
lens0021 added a commit that referenced this pull request Aug 19, 2026
)

> Stacked on #470, which is stacked on #469. Review the top commit; the
bases merge first.

`playwright install chromium` fetches three things: Chrome for Testing
(379 MiB unpacked), the headless shell (262 MiB) and ffmpeg (5 MiB).
These specs run headless and record no video, so the shell is the one
Playwright starts and the browser beside it is downloaded to be ignored.
Asking for the shell by name skips it. ffmpeg arrives either way, so
what this saves is the 379 MiB, about three fifths of the bytes in a 33s
step.

## Checked, not reasoned

Installed the shell alone into a browser directory of its own, pointed
`PLAYWRIGHT_BROWSERS_PATH` at it so Playwright could find nothing else,
and ran the suite against a real bake:

```
57 passed (14.6s)
```

`--with-deps` stays. What it installs is system libraries, which the
shell needs as much as the full browser.

If the shell were ever not enough -- a spec asking for a headed browser,
or for video -- Playwright fails naming the executable it cannot find,
so this cannot quietly test the wrong thing.

## Why not cache the browsers, as #461 suggested

zizmor refuses it. `actions/cache` in a job that also runs
`docker/build-push-action` is its cache-poisoning audit, high severity:

```
error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack
 53 |         uses: docker/build-push-action@... runtime artifacts usually published here
246 |       - uses: actions/cache@...           enables caching by default
```

Tried it first and read that, which is the same objection the comment
two lines below this change already records about setup-node's caching.
Fetching less needs no exception.

Refs #461.

---------

Co-authored-by: Claude <noreply@anthropic.com>
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