hachiflow.com
Eksporty

Ściana 200 MB: jak wyprowadzić przestrzeń na 100 GB za drzwi

Żądania przechodzące przez CDN-y i proxy mają limity rozmiaru, a eksport klienta to jedno archiwum. Przesyłanie wieloczęściowe to nudna, poprawna poprawka, ale nie nazwaliśmy jej skończoną, dopóki archiwum 260 MB nie wyszło po drugiej stronie co do bajta.

The promise and the ceiling

We sell workspaces with 100 GB of file storage, and we promise that a customer can leave with everything. A customer export is one archive. And every HTTP request that travels through CDNs and proxies has a per-request body ceiling; on our path it was 200 MB. Put those three sentences together and the conclusion is ugly: a workspace that had really used its storage could not leave.

A data-portability promise you cannot execute is worse than no promise, because the customer discovers it at the moment of leaving, the worst possible moment to learn anything. So the export path had to stop depending on the archive fitting inside one request.

The fix is boring, which is the compliment

Multipart upload: split the archive into uniform parts, upload them one after another, each comfortably under the ceiling, and let the storage layer reassemble them into a single object. The store confirms the completed whole by echoing back the size it assembled, and the client checks that echo against the bytes it sent. No cleverness, no new protocol. The ceiling stops being a property of the archive and becomes a property of a part, and parts are whatever size we say they are.

Small archives still go up in one request; the multipart machinery engages past a threshold. What matters is that the decision is made on the archive's actual size, so no workspace is ever routed into the wall again.

jedno archiwum, 260 MB 200 MB na żądanie jedno żądanie: odrzucone jednakowe części, wysyłane po kolei złożone w magazynie etag …-5 odcisk magazynu liczy części
Jedno żądanie nie przeniesie archiwum ponad limit na żądanie. Jednakowe części tak, a własny odcisk warstwy magazynu, sufiks etagu liczący części, jest pokwitowaniem, że składanie naprawdę zaszło. Przy każdym niepowodzeniu klient przerywa wysyłkę, bo częściowo wgrane części to niewidoczny, płatny magazyn.

The failure mode nothing lists

Multipart upload has one sharp edge. Until the final assembly step, uploaded parts are invisible: no listing shows them, no object exists yet, and the storage bills for them anyway. A client that crashes halfway and walks away leaves paid-for, unreachable bytes that nothing will ever surface.

So the rule is absolute: on any failure, the client must explicitly abort the upload, which tells the store to discard the accumulated parts. Our client aborts on every failure path, deliberately, because storage you cannot see is the kind of leak that survives every audit that only looks at what exists.

A green test suite was not the proof

The multipart client passed its tests against a strict fake of the storage API. Then we did the thing tests cannot do: loaded our own workspace past the old ceiling and pulled a real export, end to end, against production.

The archive came out at just over 260 MB, built in under a minute, downloaded whole, byte for byte. And the storage layer volunteered the receipt: its fingerprint for the object carried the multipart suffix, an etag ending in -5, the store's own way of saying it assembled the object from five parts. That suffix cannot appear on a single-request upload. It is the one line in the drill log that proves the new path ran, rather than the old path getting lucky with a smaller archive.

One extracted file was re-hashed and matched its content address, the export's own integrity story doing its job. The export remains what it always was: a verifiable record of your workspace, not a restore button.

Test the ceiling you sell

The lesson generalizes. Our test suite exercised the ceiling we had, with fakes; the pricing page sells a much higher one. The only honest evidence is a real workspace pushed past the point where the old path used to break, watched end to end. A 260 MB drill is not a 100 GB drill, and we will keep raising the bar, but the wall itself is gone: from here, size adds parts, not new mechanisms. Test the ceiling you sell, not the ceiling you have.

← Wszystkie notatki