Skip to content

Warn when packument ref fan-out nears the subrequest cap#43

Merged
fengmk2 merged 1 commit into
mainfrom
warn-many-refs
Jul 1, 2026
Merged

Warn when packument ref fan-out nears the subrequest cap#43
fengmk2 merged 1 commit into
mainfrom
warn-many-refs

Conversation

@fengmk2

@fengmk2 fengmk2 commented Jul 1, 2026

Copy link
Copy Markdown
Member

A cheap early-warning guard (the one thing worth watching from the perf review, not fixing yet).

A packument rebuild issues ~3 + one-per-ref R2 reads. A cold request with a large active-ref set could approach Cloudflare's per-request subrequest cap (50 on most plans, 1000 unbound). This logs a console.warn once the ref count crosses ~40, so the fan-out (a per-package meta aggregate, deferred as "F1") can be addressed before it could ever hit the cap.

Rebuilds are rare (the F5 output cache serves hits without touching refs), so this stays silent until the active-ref set is genuinely large , it's a tripwire, not a hot-path cost.

tsc clean, 73 tests pass (no behavior change; K is small in tests so it never fires).

A packument rebuild issues ~3 + one-per-ref R2 reads; a cold request with a large
active-ref set could approach Cloudflare's per-request subrequest cap (50 on most
plans). Log a warning past ~40 refs so the fan-out (a per-package meta aggregate)
can be addressed before it becomes a hard failure. Rebuilds are rare (the F5
output cache), so this stays quiet until the ref set is genuinely large.
@fengmk2 fengmk2 merged commit 39bf0ef into main Jul 1, 2026
4 checks passed
@fengmk2 fengmk2 deleted the warn-many-refs branch July 1, 2026 01:40
fengmk2 added a commit that referenced this pull request Jul 1, 2026
…o ref limit) (#44)

Removes the effective limit on the number of refs. Closes the F1
fan-out.

## Problem

The packument rebuild read one `metaKey` per configured ref (K R2
reads). A cold rebuild's subrequest count grew with the ref set, so
continuous releases would eventually push it past Cloudflare's
per-request subrequest cap , a hard ceiling on how many refs could
accumulate. (The `#43` tripwire only warned about this; it didn't remove
it.)

## Fix

A per-package aggregate the packument reads in one shot:
- `/-/publish` upserts each package's meta into `meta-index/<name>`
(`version -> meta`), a CAS read-modify-write like the refs index,
pruning expired entries on write.
- The packument reads that **one** object instead of K per-version keys.
Subrequests per rebuild are now flat , `refs-index + meta-index + npm
base + time` , **regardless of ref count**.
- A ref not yet in the aggregate (published before this deploys) falls
back to its per-version `metaKey`; that path fades as refs republish or
expire (90-day TTL). Platform packages that were never published for a
given ref still fall back to name-derived metadata.
- `/-/purge` removes from the aggregate too, so a purged build stops
being served.

Extracted the R2 etag-CAS loop into `casR2Json`, now shared by the refs
index and the meta index. Removed the `#43` subrequest-cap tripwire ,
the limit is gone.

## Trade-off (a soft cost, not a cap)

Each publish rewrites the aggregate (O(K) write), the same shape the
refs index already has, and bounded by the 90-day TTL (steady-state K =
release-rate × 90 days, not unbounded). The packument body still scales
with K (inherent to any registry) but is cached (F5) + gzipped.

## Verify

`tsc` clean, 75 tests pass, action bundle unaffected. New tests: the
packument injects a version with its per-version key **deleted**
(proving it reads the aggregate), and purge drops the version from the
aggregate.
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