Skip to content

template: every -disk worker at Lambda's 10240 MB /tmp ceiling (issue #536) - #537

Merged
espg merged 1 commit into
mainfrom
claude/536-disk-ceiling
Aug 26, 2026
Merged

template: every -disk worker at Lambda's 10240 MB /tmp ceiling (issue #536)#537
espg merged 1 commit into
mainfrom
claude/536-disk-ceiling

Conversation

@espg

@espg espg commented Aug 26, 2026

Copy link
Copy Markdown
Member

Closes #536.

Raises WorkerDiskTmp to Lambda's 10240 MB EphemeralStorage ceiling at every memory size, superseding issue #235's memory + 2048 (under which only the 8192 variant reached the ceiling).

WorkerDiskTmp:
  "2048": {SizeMb: 4096}   ->  {SizeMb: 10240}
  "4096": {SizeMb: 6144}   ->  {SizeMb: 10240}
  "8192": {SizeMb: 10240}      unchanged

Why the rule changed

The thing /tmp gates does not scale with memory. zagg.processing.spill._default_block_bytes is min(0.2 x memory x K, 0.45 x free_tmp) with K = 4 ** (group_order - parent_order), and K is 64 on the production HEALPix grids:

memory memory term disk term (old)
2048 MB 26 GiB 2.70 GiB
4096 MB 51 GiB 2.70 GiB
8192 MB 102 GiB 4.50 GiB

Disk bound the block by 6-23x at every tier. Memory never chose the block size.

The GEDI waveform reducers (build_waveform_digest, single_shot_value, shot_count, shot_number) have no cross-block fold law, so that config is exact-single-block-only: crossing the threshold raises SpillOverflowError rather than emit a combined-but-wrong result. 249 of 2,726 shards on the CA GEDI build died exactly there, all of them dense (0% failures below 50 granules, 74% in the 80-100 band).

Measured, not assumed

The 10 densest failed shards — 98-103 granules, including all four >100-granule shards in the map — re-run on process-shard-8192-disk (10240 MB /tmp):

granules duration peak spill blocks closed
103 694 s 3.56 GiB 0
102 688 s 3.53 GiB 0
101 682 s 3.38 GiB 0
99 679 s 3.46 GiB 0
98 732 s 3.55 GiB 0

10/10 succeeded, spill_blocks_closed = 0 throughout (single-block, exact — the correctness condition), peak 3.56 GiB against the 4.50 GiB ceiling: 21% headroom. Since 10240 MB is Lambda's ceiling, 4.50 GiB is the largest spill block obtainable on any Lambda, and the measurement says it covers the whole CA map.

Cost

Ephemeral storage above 512 MB bills at $0.0000000309/GB-s. Over a CA-sized run (~681,500 invocation-seconds) the extra 4 GB is $0.08, against $48.65 of compute — 0.2%.

What this does NOT claim

That memory can now be dropped. The spill threshold is memory-independent; the 900 s timeout is not — vCPU follows memory, the config runs shard_workers: 4, and the dense band measured 673-732 s at 8192 MB, only 19-25% under the wall. Whether 2048 or 4096 clears that band in time is a separate timing test. Both the template comment and the changelog say so explicitly, because "disk parity means capability parity" is the wrong lesson to take from this PR.

Phases

Single phase — a three-value mapping change plus the prose and tests that pin the old rule. Splitting it would be artificial file-splitting (CLAUDE.md section 2).

  • mapping to the ceiling; WorkerMemorySizes description and Mappings comment rewritten; test_lambda_build.py assertions updated.

How it was tested

pytest -q tests/test_lambda_build.py -> 39 passed, 1 skipped, plus the one failure below.

  • test_foreach_expands_to_six_variants now asserts tmp_mb == _DISK_TMP[size] == _LAMBDA_EPHEMERAL_CEILING_MB for all three sizes.
  • _DISK_TMP is derived as dict.fromkeys(_SIZES, _LAMBDA_EPHEMERAL_CEILING_MB) rather than restated, so it cannot drift from the constant — and because a derived table would silently agree with a template that regressed, the test also asserts the mapping as literally written in the YAML.
  • test_size_list_and_disk_mapping_stay_in_sync is unchanged and still passes (keys still cover WorkerMemorySizes).

ruff check --select=E,F,W,I --ignore=E501 src tests and ruff format --check src tests clean.

test_lambda_build.py::TestFunctionBuild::test_function_build_succeeds fails locally with No matching distribution found for zarr>=3.1.5 — a pre-existing offline-sandbox failure, unrelated, and green in CI on #535.

Deploy notes for whoever runs this — please read before the stack update

Two things found while checking that this needs no release. Neither is part of the diff; both bite at deploy time.

  1. The live stack has drifted. zagg-backend declares LayerS3Key/FunctionS3Key at 0.49, while the fleet runs 0.52 code on layer :61, updated outside CloudFormation at 02:25 UTC. Any stack update reconciles that, so this deploy will also re-point code and publish a new layer version. Harmless if the resolved minor is 0.52 — it is what is already running — but it is not the config-only update it looks like.

  2. stand_up.sh unpinned can downgrade the fleet. It builds version-scoped keys (dist_key -> <prefix>/<minor>/<zip>) and resolves the minor from LAMBDA_VERSION=latest -> explicit LAMBDA_VERSION -> git describe --tags -> installed zagg, then passes every parameter explicitly (no "use previous value"). From a feature branch git describe returns the newest tag reachable from HEAD: on claude/328-demo-07-minimal that is 0.47.0, which is staged and would pass every check in the script while silently reverting the fleet past the issue fleet cannot write large objects to source.coop: x-amz-acl is rejected on UploadPart (400 InvalidArgument) — MVP blocker #534 ACL fix.

    Deploy as LAMBDA_VERSION=0.52 ./deployment/aws/stand_up.sh, or from a checkout sitting on the 0.52.0 tag.

Correctly, no new release is needed: this touches no Lambda code.

Questions for review

  1. Should 2048 be at the ceiling too? Included here on the "disk is free, memory is what costs" reasoning, and it makes the mapping uniform. The counter-argument is that a 2048 worker cannot use a 4.50 GiB block within 900 s anyway, so the entry is aspirational. Left uniform because a non-uniform table needs a rule, and the old rule is what this PR removes.
  2. Should out-of-band fleet code updates keep existing? Finding (1) above is how a 0.47 downgrade becomes a one-command accident. Out of scope here; flagging it as a process question.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

raise every -disk worker to Lambda's 10240 MB /tmp ceiling: the spill block is disk-bound, and 249 CA GEDI shards fail on it

1 participant