Warm the file cache on a background worker thread#223
Open
freshlogic wants to merge 8 commits into
Open
Conversation
The first request for an uncached file read and processed it synchronously (Sass, Babel, Snockets, UglifyJS, gzip), blocking the event loop and slowing the whole site. Extract the processing pipeline into a shared processor module and run it in a background worker thread that lazily reads every file in the directory, posting finished cache entries back to the main thread. The synchronous read stays as the per-request fallback, so behavior is unchanged for any file not yet warmed. Warming is skipped while watching (it registers discovered dependencies on the main thread) and when options carry functions (which can't be cloned into the worker), to keep cached output identical to the synchronous path. https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99
Spawning one worker per electricity.static() instance loaded the heavy transform libraries (Babel/Sass/UglifyJS) once per instance and competed for CPU. Use a single lazily-created worker that all instances submit warm jobs to, tagged by job id so each instance's cache receives its own entries. https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99
Replace the single warm worker with a shared pool sized to max(1, cpus - 1), leaving a core free for the event loop. Each warm job is fanned out across the pool, with every worker processing a disjoint, deterministic shard of the directory's files so a single directory warms in parallel. Each worker keeps its own processor, so a CSS file's url() dependencies still resolve within that worker even when the referenced asset lives in another shard; deterministic hashing keeps every entry byte-identical to a synchronous read. https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99
Use os.availableParallelism() instead of os.cpus().length so the pool respects the process's CPU affinity mask (e.g. cpuset pinning) rather than always counting every host core. https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99
Coverage Report for CI Build 26346126154Coverage decreased (-2.0%) to 98.041%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Replace the bespoke hasFunction scan with a try/catch around the worker postMessage. Options that can't be structured-cloned (e.g. a Sass importer or a Babel plugin passed as a function) now skip warming for that instance via the caught DataCloneError, which is simpler and covers any non-cloneable value rather than only functions. https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99
…-background-SjTlo
Match the org convention used elsewhere (e.g. exports.static in index.js): attach public functions to exports directly instead of a trailing module.exports block. Internal references go through exports.X since named function expressions aren't bound in module scope. https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99
Cover the startWarmer DataCloneError path: passing a Sass importer (a function) must not crash static() — warming is skipped for that instance and the synchronous read still serves the file. https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99
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.
The first request for an uncached file read and processed it
synchronously (Sass, Babel, Snockets, UglifyJS, gzip), blocking the
event loop and slowing the whole site. Extract the processing pipeline
into a shared processor module and run it in a background worker thread
that lazily reads every file in the directory, posting finished cache
entries back to the main thread. The synchronous read stays as the
per-request fallback, so behavior is unchanged for any file not yet
warmed. Warming is skipped while watching (it registers discovered
dependencies on the main thread) and when options carry functions
(which can't be cloned into the worker), to keep cached output identical
to the synchronous path.
https://claude.ai/code/session_013nWBHBH1uYqZ35q6TTks99