Skip to content

feat(orchestration): gzip location snapshot publishes - #1378

Closed
kvlonge wants to merge 3 commits into
mainfrom
feat/gzip-location-publish
Closed

kvlonge wants to merge 3 commits into
mainfrom
feat/gzip-location-publish

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Why

A location publish posts its whole snapshot as JSON, and the server caps bodies at 64 MiB. A 10,282-model project already makes a 62.0 MiB snapshot, so larger projects cannot publish. Gzipped it is 2.8 MiB.

Changes

  • sqb location sends snapshots with Content-Encoding: gzip.
  • The publish route keeps the 64 MiB wire bound. After the location token is authenticated, it streams gzip into the JSON parser through a 320 MiB decompressed bound and stops once it is passed, without buffering the output.
  • Only gzip is accepted: another encoding gets 415; a body over either bound gets 413.
  • A server that refuses the encoded body with 400 or 415, as older servers do, gets the snapshot once more as plain JSON, unless the plain body is over the wire bound; then its refusal is reported as is.
  • The generated TypeScript client includes 413 and 415.

Verification

  • HTTP contract tests, failing on main: an unauthenticated gzip bomb gets 401 undecompressed; an authenticated bomb gets 413; plain JSON over 64 MiB gets 413; br gets 415 and non-gzip 400; a 10,282-node snapshot over 64 MiB publishes; an invalid one keeps its 400; older servers get the plain resend.
  • sqb server plus sqb location publish publish a generated 10k-model DuckShop end to end.
  • Server peak RSS (/usr/bin/time -v, fresh sqb server, SQLite): 480 MiB for that DuckShop publish (idle 15 MiB). A parsed snapshot holds about 7.6x its JSON: a body just under 512 MiB peaked at 3,879 MiB, so the bound is 320 MiB, 4x the snapshot with column lineage (74 MiB). Just under 320 MiB peaked at 2,420 MiB; 328 MiB got 413 at 1,610 MiB.
  • Gzip cost on the 62.0 MiB snapshot (5 alternating runs, medians): compress 0.49 s CPU; server gunzip and parse 0.81 s against 0.66 s plain.
  • make check-ci passes; the publication suite and TS client passed on the first commit.

DuckShop: no edge case added, because this changes the HTTP transport, not a project shape, data value or lifecycle sequence.

A location now sends its snapshot with Content-Encoding: gzip. The server
keeps the 64 MiB wire bound and, after authenticating the location token,
streams the body through a 512 MiB decompressed-size bound into the JSON
parser. Encodings other than gzip get 415, and a body over either bound gets
413. A server that refuses the encoded body with 400 or 415 gets the
snapshot again as plain JSON, so new locations still publish to older
servers.
…ge to resend plain

A snapshot whose plain JSON exceeds the wire bound can never be accepted
uncompressed, so a 400 for the gzip body is returned as is instead of
being masked by a second upload that ends in 413.
A parsed snapshot holds about 7.6 times its JSON size on the server, so
a body just under 512 MiB peaked at 3.8 GiB RSS. 320 MiB keeps four
times the headroom of a 10,000-model project with column lineage.
@kvlonge
kvlonge marked this pull request as ready for review November 8, 2026 18:36
@kvlonge
kvlonge enabled auto-merge (squash) November 8, 2026 18:36

kvlonge commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

Folded into the single combined sqlbuild PR (D625/D626), which the SQLBuild lane is assembling now and opens once #1377 lands. Branch kept.

@kvlonge kvlonge closed this Nov 8, 2026
auto-merge was automatically disabled November 8, 2026 21:16

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant