Skip to content

F19: bound Graphile resident admission and heap headroom - #1853

Open
Zetazzz wants to merge 4 commits into
mainfrom
graphile-resident-admission-c8f5bfd9
Open

Zetazzz wants to merge 4 commits into
mainfrom
graphile-resident-admission-c8f5bfd9

Conversation

@Zetazzz

@Zetazzz Zetazzz commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Concurrent cold cache misses previously started resource allocation before a resident slot was available. F19 reserves resident count and process-heap headroom first, accounts for disposal in progress, and waits for evicted resources before admitting replacements.

Rebased onto main 299b3920; tested head 21a42e45. This main-based PR includes the F04/F17 prerequisites. #1855 also targets main and includes this PR's commits; the two diffs overlap.

Measured conclusion: pre-allocation admission works, but the measurements do not establish a stable speedup or RSS reduction. Evaluate this as cold-burst resource protection, not a demonstrated throughput optimization.

The existing measured cache heap budget remains enforced through cacheGraphileInstance, including oversized-build release and reservation cleanup. Existing GRAPHILE_CACHE_MAX_HEAP_BYTES remains distinct from the new process-watermark setting GRAPHILE_CACHE_HEAP_MAX_BYTES. Configuration parsing/precedence belongs to graphql-env; main's current presets, scoped introspection, request ownership and storage-cache invalidation are retained. Cleanup failure permanently latches admission unavailable until process restart.

Measured medians, three runs per row; elapsed time completes all requested builds and validation reads:

Scenario main time (ms) F19 time (ms) main peak RSS (MiB) F19 peak RSS (MiB)
Loose, 1 cold key 1504 1558 176.12 177.39
Loose, 4 cold keys 3498 3333 243.73 250.80
Loose, 8 cold keys 7686 6660 285.27 291.04
Tight, 8 cold keys, all completed 7130 6313 292.30 294.87

At tight capacity 4, main started all 8 creates concurrently. F19 limited concurrent creates to 4: 4 initial calls succeeded and 4 returned SCHEMA_CAPACITY_EXHAUSTED before service allocation. After the entire initial wave settled, one immediate in-process retry wave completed the remaining 4. The all-completed timer starts before the initial calls and includes rejection time, the initial-wave wait, retry work and scheduling; there is no artificial network/backoff delay. Real client retry latency may be higher. This compares equal completed work, not 4 successful builds against 8.

The loose-8 median is 13.4% lower, but ranges overlap substantially: main 6580–7810 ms, F19 6100–7496 ms. Three repetitions do not support a reliable general speedup, and RSS did not decrease.

Measured on 2026-11-04: Node 24.20.0, PostgreSQL 18.6, 3 available CPUs, approximately 4 GiB RAM, --expose-gc --max-old-space-size=768. Each fresh worker builds a 24-table schema and validates a seeded GraphQL read. Three repetitions per arm/scenario, randomized sequential order; 36/36 runs passed across main/F19/F21. Every successful build produced the same schema hash and query result.

Loose capacity is 50 residents; tight capacity is 4. Both measured resident heap budget and process heap watermark are set to 4 GiB, with a 64 MiB build reserve, to isolate count/coordinator behavior. This does not test default heap-watermark tuning or OOM prevention. No subscriptions are used.

The validation read runs inside the create callback before publication to prevent eviction racing validation. Consequently, permit occupancy includes query time: this is a cache-layer cold build-and-query microbenchmark, not production HTTP latency/throughput or a bound on all SQL concurrency. RSS peaks cover the entire run, including retry waves.

Validation at the rebased head:

  • CI: 17/17 jobs passed, manually dispatched on the exact head after retargeting.
  • Cache: 69 tests; graphql-env: 75 tests plus snapshot; errors: 51 tests; express-context: 135 tests; focused server: 38 tests.
  • Real PostgreSQL/scoped-routing HTTP scenarios: 7/7 passed.
  • Relevant CJS/ESM package builds, frozen-lockfile install and diff checks passed.

Raw measurements, samples and runtime/source provenance are retained in the task workspace at /workspace/scratch/admission-rebase/bench/results-24.json; grouped medians/ranges are in results-24-summary.json, alongside the worker, runner and analysis scripts.

@tenki-reviewer

tenki-reviewer Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Review complete. 🟠 1 high

💬 Inline comments (1)

  • 🟠 Disposal failure permanently bricks all schema admission — admission.ts:71

This PR introduces a memory-aware admission and eviction controller for the plan cache: admission.ts gates schema builds against a heap budget, admitted-build.ts tracks per-owner reservations and released entries, and graphile-cache.ts/create-instance.ts route build and disposal through it. The GraphQL server wires the new build flow into the request-lifecycle middleware and explorer server with single-flight deduplication, while graphql/env gains parsing/validation/merge helpers used to feed cache and config options. A single high-severity finding remains in the admission controller's failure latch.

Files Change
graphile/graphile-cache/src/admission.ts, admitted-build.ts, graphile-cache.ts, create-instance.ts Add heap-budget admission, per-owner reservations, and eviction/disposal semantics for the plan cache.
graphql/server/src/middleware/graphile.ts, graphql/explorer/src/server.ts Route instance building through the new admission flow with single-flight deduplication.
graphql/env/src/env.ts, merge.ts, validation.ts Add env parsing, cross-field validation, and merge-priority helpers for cache/config options.
graphql/types, packages/errors Wire new cache/config types and schema-capacity error registry entries.

Reviewed commit: c83256e

@tenki-reviewer tenki-reviewer Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds a process-heap admission/eviction controller for the schema plan cache, wires it through the GraphQL server instance build path, and adds env/config validation helpers in the graphql/env package.

Key findings

  • 🟠 Disposal failure permanently bricks all schema admission — admission.ts:71

@Zetazzz
Zetazzz force-pushed the graphile-resident-admission-c8f5bfd9 branch from 71ead47 to 21a42e4 Compare November 4, 2026 05:24
@Zetazzz
Zetazzz changed the base branch from graphile-build-identity-c8f5bfd9 to main November 4, 2026 05:25
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