Sync the self-hosting stack

This commit is contained in:
2026-09-26 15:49:04 +02:00
parent 1aa6e9d05f
commit 248d6c2d52
8 changed files with 274 additions and 18 deletions
+41 -1
View File
@@ -141,9 +141,49 @@ spec:
cpu: 500m
# Not generous — honest. A terminal recording holds up to 8 MiB of Buffers in heap
# for the life of the session, and argon2 takes 64 MiB per share verification.
#
# Attached and uploaded files add four holders, every one capped, so that their sum is
# a number rather than a hope. Their figures are MEASURED on this image, in a cgroup
# like this pod's, not estimated — the estimates were five to seven times too low.
#
# Uploads being checked and stored: 3 at a time (`files/upload-slots.ts`). Prisma is
# what costs: its JSON protocol turns the bytes into base64, then into a request
# string, and its engine copies that again. A 10 MiB file adds ~200 MiB of RSS while
# it is written; a workspace image with the 3 MiB copy of it prepared for the model,
# ~310 MiB, and ~330 to 360 MiB each with three at once, three bursts in a row. So
# ~1.1 GiB. Six at a time, as this once allowed, took a 2 GiB container to 1.8-1.95
# GiB with nothing else in it, and three such bursts were OOM-killed.
#
# Files read back — their bytes over HTTP, a window of their text for the viewer or
# for the assistant's `read_attachment`: 8 at a time, up to ~40 MiB each (a 10 MiB log
# is decoded whole, 25 to 39 MiB measured, until its window is cut). So 320 MiB.
#
# Images for the model: 64 MiB of `data:` URLs, reserved before a byte is read, so the
# same 64 MiB also bounds what is being read for them at any instant — at most ~48 MiB
# raw, which Prisma's transfer copies a few times more for the milliseconds a request
# takes to build. So ~200 MiB at the worst instant.
#
# A PDF worker is the one without a flat cap. `resourceLimits` bounds its V8 heap
# (192 MB, plus 32 MB of young generation) and NOT its ArrayBuffers, where a
# decompressed stream lives. Those are read from outside every 50 ms and the worker is
# killed past 128 MB, which a buffer doubling between two reads can overshoot to ~256
# MB. So one hostile file can hold up to ~500 MB before it dies, two ~1 GB. Measured:
# two decompression bombs at once added ~310 MB to the process, both refused in under
# two seconds.
#
# Every holder full at once is therefore ~2.5 GiB (1.1 GiB of uploads, 320 MiB of
# files read back, ~200 MiB of images, ~1 GB of PDF workers), on top of the API itself
# (~200 MiB once booted): ~2.75 GiB. That cannot fit 2Gi at any upload concurrency
# worth having — at 2Gi, one upload at a time beside two hostile PDFs is all there is
# room for — so the limit is 3Gi, with ~250 MiB left for the terminal recordings and
# share verifications above. It runs well past the room above this request, and that
# is deliberate: the request is what the scheduler sets aside for an ordinary day, not
# for the worst minute. If more margin is ever wanted, the levers are the PDF worker's
# own caps (`files/pdf-text.ts`) and keeping an upload's bytes out of Prisma's JSON
# protocol — not fewer upload slots.
memory: 1Gi
limits:
memory: 2Gi
memory: 3Gi
securityContext:
runAsNonRoot: true
runAsUser: 1000