Loading…
Reference in a new issue
No description provided.
Delete branch "feat/991-archive-on-disk"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #991 (part 2, PR A). Addresses #1054 but does not close it: see "What stays open".
Summary
app/services/archive_zip.py), not held in memory. Every read from the archive is bounded.GET/PUT /api/admin/settings/import-limit, audited.location = /api/campaigns/importhas no body limit and no request buffering; the backend enforces the setting./api/keeps110m.data.jsonwhose root is not an object is a 422. It was a 500.The limits
data.jsonsizedata.jsonvaluesmedia_max_upload_bytes(8 MB)Why
data.jsonis capped at 8 MBIt is the one part parsed in memory, in a 512 MB backend that runs at 340 to 425 MB warm. Python holds a string with one emoji at four bytes a character, twice. At the first cap tried (32 MB), a 32 KB upload got a worker OOM-killed on the real stack.
Measured in a 512 MB container at 8 MB / 400,000:
"Dearest found" is the worst shape tried, not a proof.
Production's 21 sessions hold 858 KB of transcript and 1,618 segments, so a real file is several times under both caps today.
What stays open (#1054)
oom_killstayed 0, but the sampled peak reached 505 MB of 512 MB.Changelog
changelog.d/991-archive-on-disk.changed.mdTest plan
7167 passed, 14 skipped, 107 deselected.3806 passed | 1 skipped, eslint 0 errors.tests/export, the nginx limit test, the compose media test and both wiki reader audits:332 passed. Lint clean. Version and changelog checks OK. All 16 coverage scripts reportunclassified: none.183 passed.Content-Length: 413;oom_kill 0, nothing left in/tmp.For review
.bodyand.titleread-audit lists gained an entry, because the export's file-writing moved into a nested function. Same reads, same GM-only route. Those lists are a privacy control, so it is worth a glance.asyncio.to_threadleft about 17 MB in each pool thread's arena.🤖 Generated with Claude Code
Independent review of
84d1c76b: not to be merged yet. Two confirmed defects let any signed-in user push the backend past its memory with a small upload. Fixes are in progress on this branch.Findings
zipfiledecompresses each compressed block whole before truncating to the declared size. A 741-byte zip took memory from 22 MB to 1,626 MB before the refusal.mainhas the same hole. Fix: refuse any entry that is not stored or deflated.zipfile. A classic end record that says "1 entry", with a zip64 locator before it, passes the pre-check;zipfilethen builds every entry. 400,000 empty entries cost 230 MB. Fix: read the same recordzipfilereads, and pin the two together with a test.Found sound
Not checked by the review: behaviour in a running stack (it read the code and ran the module locally), and the frontend.
All five review findings fixed in
d7e755ac. Each has a test that fails on the earlier commit.zipfilereads, compares its answer withzipfile._EndRecData, and refuses the file if they disagreeRetry-After; 429; 408read_jsoncatchesValueError_write_export_entriesThe reviewer's two proof files, re-run by me against
d7e755acRan at this commit
tests/export, the nginx limit test and both wiki reader audits: 344 passed.Not run at this commit: the full suites (CI), and the end-to-end run through nginx. The new 503, 429 and 408 answers are covered by route tests only.
The in-flight cap is per worker process, so the disk bound is workers × 2 × the import limit.
docs/OPERATIONS.mdsays so.