Repository navigation
Shrink the Wattsi scratch footprint, always clean it up, and log where builds die - #219
Merged
Merged
Conversation
An instance on a 512 MiB flavor was OOM-killed while unzipping the second whatwg/html build, with Node's own RSS around 110 MB. The scratch files are the likely culprit: each Wattsi zip holds far more than we use, and both zips plus both unpacked trees sat in the tmp dir at once. - Extract only multipage-html/ (plus xrefs.json from the head build), and delete each zip once it is unpacked. - Clean up the per-PR scratch directory when the job ends, whatever the outcome. It used to be removed only at the end of a successful cacheAll(), so failed or skipped builds left their files behind. - Update DEPLOYMENT.md: the app runs on nano, and describes what an OOM kill looks like in the log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fa64HAQWfNnsexnq3duiT
The crash on whatwg/html#12263 could only be located by noticing which `ls` line was missing, and Node's own memory numbers looked healthy while the machine ran out. - memory() snapshots now add the machine's MemTotal, MemAvailable and Shmem (tmpfs counts there) from /proc/meminfo, and the space used on the tmp dir's filesystem, where each can be read. - Each Wattsi build step (fetch, extract, diff, rewrite, html-dfn.js) logs when it starts and how it ended, with its duration, a memory snapshot and the size of the PR's scratch dir. The diff's file counts are logged too. - The unpacked-files listing uses readdir instead of spawning `ls`, only runs when debug logging is on, and no longer goes through a process.nextTick that did nothing. - WattsiClient takes an optional logger, for tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fa64HAQWfNnsexnq3duiT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The instance (on
nano, 512 MiB) was OOM-killed while building whatwg/html#12263. The log ends with a bareKilledfrom the start script and no shutdown lines. Node's own RSS stayed around 110 MB throughout, and the one-minute memory snapshots arrived later and later in the minutes before the kill. The job died after unzipping the head build, while unzipping the merge-base build. The likely culprit is the Wattsi scratch files in the tmp dir counting against the machine's memory: both zips plus both fully unpacked builds were there at once. This still needs confirming on the instance (df -h /tmp). The logging added here should confirm or rule it out next time.Changes
Smaller footprint (
lib/wattsi-client.js)multipage-html/from each build, plusxrefs.jsonfrom the head build, instead of the whole zip. Each zip is deleted once it's unpacked. A missingxrefs.jsonmakesunzipfail with a clear error, which is fine since its upload needs it anyway.Always clean up (
lib/controller.js,lib/models/pr.js)handlePullRequest()now calls a newPR.cleanup()in afinally. Before, the per-PR scratch directory was removed only at the end of a successfulcacheAll(), so failed, aborted or skipped builds left their files behind. A failed cleanup only logs a warning and never changes the job's result.Debugging (
lib/logger.js,lib/wattsi-client.js)memory()snapshots (per request, every minute, on exit) now also carry the machine'smemTotal,memAvailableandshmemfrom/proc/meminfo, andtmpUsedfor the tmp dir's filesystem, where each can be read.html-dfn.js) logs at debug level when it starts and how it ended, with its duration, a memory snapshot and the size of the PR's scratch dir. If the process dies, the laststartingline names the step. The diff's modified/added/removed/unchanged counts are logged too.readdirinstead of spawningls, only runs when debug logging is on, and no longer goes through aprocess.nextTickthat did nothing.WattsiClienttakes an optional logger, for tests.DEPLOYMENT.md: the flavor is nownano, the Wattsi scratch-space description matches the new behaviour, and it describes what an OOM kill looks like in the log and which fields to read.Tests
WattsiClient.unzip: extracts only the expected members, deletes each zip after extraction, and keeps the zip and rejects whenunzipfails.Controller.handlePullRequest cleanup: cleans up after a successful build, a failed build and a skipped update, and a failing cleanup doesn't change the result.WattsiClient.step/logListing: start/done/failed lines with scratch size, and the listing is skipped when debug is off and never fails the build.memory(): the machine fields are present on Linux.npm test: 163 passing. I also rangetFilenames()end to end on local fixture zips with realunzip/diffand the pretty logger. Unused files were left out of the extraction, and each step logged as expected.Not in this PR
PR.init(), before the controller checks whether the PR needs an update, so skipped whatwg/html events still build. Moving it is planned as a follow-up, after an end-to-end test of thehandlePullRequest()pipeline.getPreviewFiles(),cacheAll()and the body view currently have no coverage.🤖 Generated with Claude Code
https://claude.ai/code/session_017fa64HAQWfNnsexnq3duiT