Repository navigation
fix(cache): bound shared transform cache memory - #835
Merged
privatenumber merged 12 commits intoAug 30, 2026
Merged
Conversation
Replace the directory-wide metadata index with up to eight newest-first probes across the live retention buckets. Keep lookups read-only and let writers own cache creation and automatic maintenance. Stream expiry in batches of at most 64 scanned entries, with bounded deletions and an in-flight guard. Refs: privatenumber#834
Seed the same 150000 real files without changing the 32 MiB child cap or application assertions. Await batches of 64 asynchronous writes to keep the watchdog responsive and bound open descriptors. Name the empty and populated controls separately so pending or failing output identifies the scenario. Refs: privatenumber#834
Calibrate the real-file regression to 75,000 entries with a stricter 16 MiB heap cap. The original owner OOMs in five of five runs while the repair passes, and repeated empty controls also pass at 12 MiB. Preserve the same real-loader probe, 64-write batches, owned cache-enabled environment, and exit/stdout assertions. Remove temporary diagnostics and restore direct fixture disposal without increasing any deadline. Refs: privatenumber#834
steipete
marked this pull request as ready for review
August 28, 2026 19:29
This was referenced Aug 28, 2026
Owner
|
This issue is now resolved in v4.23.13. If you're able to, your sponsorship would be very much appreciated. |
Contributor
Author
|
sweet, thank you! |
Contributor
Author
|
I already sponsor you through the OpenClaw Foundation, and just increased level from bronze to silver. Thanks again! |
Owner
|
Thanks @steipete ! 🙌❤️ |
1 task
tiualvin
pushed a commit
to tiualvin/beyond-every-art
that referenced
this pull request
Sep 4, 2026
Bounds the shared transform cache memory (privatenumber/tsx#835). Replaces #139, which Dependabot closed and reopened as this once #142 landed the group's other half — eslint-config-next 15.5.25, which had to move with `next` rather than on its own.
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.
Problem
tsx stores transformed modules in a shared disk cache so later processes can reuse them. The first cache lookup currently reads every filename into an in-memory index, including entries unrelated to the requested module.
As the shared cache grows, a small TypeScript program can exhaust its heap before its entrypoint runs. A cache with 713,453 unrelated entries reproduced the failure at a 128 MiB heap limit, and expiration of 100,000 entries could also exhaust memory after execution. Fixes #834.
Changes
Cache reads now probe only the requested SHA-1 key in the current and previous seven timestamp buckets. A lookup therefore uses constant memory regardless of how many unrelated files share the cache. Valid hits remain cached in the process, corrupt current entries can fall back to an older live entry, and reads do not create or maintain cache directories.
Writes still create the cache and schedule best-effort maintenance. Expiration now streams directory entries and processes them in batches of 64, which bounds outstanding unlink promises without retaining a directory-wide index. The cache filename format and seven-bucket retention policy remain unchanged.
The regression guard asserts that lookup never calls
readdirSync(). It fails against the original implementation with one directory enumeration and passes with the bounded lookup. The focused suite also covers live-window lookup, corrupt entries, expiration boundaries, malformed filenames, and concurrent cache writers.