CS-11029: in-process inflight dedup for #moduleCache transpile#4752
Draft
Conversation
Two concurrent in-process readers that miss #moduleCache for the same path used to each call transpileJS independently (50–500 ms of babel + ember-template-compilation + decorator transforms + scoped-css). Output was bit-identical; the second pass was wasted CPU. Adds Realm.#inFlightTranspiles — a Map<LocalPath, Promise<…>> keyed by local path. The first caller to miss the cache installs a pending entry; concurrent same-path callers await the same promise instead of running babel again. Identity-checked .finally cleanup mirrors CachingDefinitionLookup.#inFlight — a newer pending entry installed after invalidate drops the slot is preserved when an older promise eventually settles. invalidateCache (via the shared #dropModuleCacheEntry helper from CS-11028) drops the in-flight entry so post-invalidate callers don't join a stale transpile whose cache.set would just be discarded by CS-11028's generation guard anyway. Existing waiters still get the old promise's bytes — their requests preceded the invalidate, so pre-invalidation bytes are correct for them. The realm exposes __testOnlyGetTranspileCallCount / __testOnlyGetInFlightTranspileCount so dedup tests can assert "exactly one transpile call serviced N concurrent same-path readers" and "the slot released on settle" directly rather than inferring it from timing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Host Test Results 1 files 1 suites 1h 46m 37s ⏱️ Results for commit 5e2aa2b. For more details on these errors, see this check. Realm Server Test Results 1 files 1 suites 14m 55s ⏱️ Results for commit 5e2aa2b. For more details on these errors, see this check. |
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on #4750 (CS-11028). Review/merge that first.
Summary
Realm.#inFlightTranspiles— aMap<LocalPath, Promise<…>>keyed by local path. The first caller to miss#moduleCacheinstalls a pending entry; concurrent same-path callersawaitthe same promise instead of each running babel from scratch (50–500 ms per duplicate transpile saved).loadModuleFromDiskto delegate the materialize + transpile step to#transpileModuleDeduped/#materializeAndTranspile. Public behavior unchanged — same response shape, same etag, same error handling..finallycleanup mirrorsCachingDefinitionLookup.#inFlight(CS-10947) — a newer pending entry installed after an invalidate drop is preserved when an older promise eventually settles.#dropModuleCacheEntry/#dropAllModuleCacheEntrieshelpers from CS-11028 now also drop the in-flight entry, so every invalidation site (writeMany, delete, file-watcher callback, executable-invalidation cascade, full-index clear, etc.) clears in-flight too. Existing waiters on a dropped promise still receive its bytes — their requests preceded the invalidate, so pre-invalidation bytes are correct for them. New callers don't join the stale transpile because it's no longer in the map.__testOnlyGetTranspileCallCount()and__testOnlyGetInFlightTranspileCount()let the dedup tests assert "exactly one transpile call serviced N concurrent same-path readers" and "the slot released on settle" directly rather than inferring it from timing.Same shape as CS-10947 for
CachingDefinitionLookup. Stacks well with CS-11028: the inflight dedup catches the "many readers, one transpile" case; the generation discard catches the "transpile completed against pre-invalidate bytes" case.Linear: https://linear.app/cardstack/issue/CS-11029
Test plan
🤖 Generated with Claude Code