Found while working #4482. Bun reads a child's stdout as fast as the child writes it, whether or not anyone reads the stream. That holds for Bun.spawn and for node:child_process, paused or not. Probe on Bun 1.3.14: head -c 300000000 /dev/zero exits within 1.5 s with nothing reading, and RSS is around 710 MB.
So git upload-pack writes the whole pack into the forge's memory and exits, and the pack then goes to the client from that buffer. A 200 MB clone over a slow link holds about 200 MB of the forge's memory for as long as it lasts. A few at once is past a 512 MiB cell, and a cgroup OOM kill resets every connection: curl 56 Recv failure: Connection reset by peer … early EOF. That may well be part of what trevato/arm hit. It also means the old 5-minute kill rarely hit a running git, because git had usually exited already.
#4482 limits the damage. The deadline follows the stream, so a client that stops reading for 30 s has its buffer cut and freed. A slow client that keeps reading still holds its whole pack.
Done when: a pack transfer holds a bounded amount of forge memory (a few MiB), whatever the pack size and client speed. For example: stop reading git's stdout while the client is behind (a pipe Bun does not drain eagerly, or a socket/FIFO read under backpressure). A test spawns a 200 MB upload-pack behind a client that is not reading and asserts that RSS growth stays bounded and that git is still running (blocked on its pipe).
Found while working #4482. Bun reads a child's stdout as fast as the child writes it, whether or not anyone reads the stream. That holds for
Bun.spawnand fornode:child_process, paused or not. Probe on Bun 1.3.14:head -c 300000000 /dev/zeroexits within 1.5 s with nothing reading, and RSS is around 710 MB.So
git upload-packwrites the whole pack into the forge's memory and exits, and the pack then goes to the client from that buffer. A 200 MB clone over a slow link holds about 200 MB of the forge's memory for as long as it lasts. A few at once is past a 512 MiB cell, and a cgroup OOM kill resets every connection:curl 56 Recv failure: Connection reset by peer … early EOF. That may well be part of what trevato/arm hit. It also means the old 5-minute kill rarely hit a running git, because git had usually exited already.#4482 limits the damage. The deadline follows the stream, so a client that stops reading for 30 s has its buffer cut and freed. A slow client that keeps reading still holds its whole pack.
Done when: a pack transfer holds a bounded amount of forge memory (a few MiB), whatever the pack size and client speed. For example: stop reading git's stdout while the client is behind (a pipe Bun does not drain eagerly, or a socket/FIFO read under backpressure). A test spawns a 200 MB upload-pack behind a client that is not reading and asserts that RSS growth stays bounded and that git is still running (blocked on its pipe).