[6.x] Reset memoized Stache state between jobs instead of disabling it process-wide - #15126
Open
edalzell wants to merge 1 commit into
Open
[6.x] Reset memoized Stache state between jobs instead of disabling it process-wide#15126edalzell wants to merge 1 commit into
edalzell wants to merge 1 commit into
Conversation
…ling it for the whole worker process Statamic::isWorker() disabled in-process memoization for the entire life of a queue worker whenever the running command was queue:*/horizon:*, instead of just resetting it between jobs. That meant every single access within one job fell back to a cache-store round trip (or full disk listing), making queued indexing dramatically slower per document than the identical work run synchronously. Store/ContainerAssetsStore/Index are container singletons that persist for the whole worker process, so they need an explicit reset at job boundaries - added via a new JobProcessing listener (only active when isWorker() is true, so sync dispatch is unaffected). AssetContainer/AssetContainerContents are Blink-backed, and Laravel's real queue:work daemon loop already clears resolved facade instances before every job, so their isWorker() gates were redundant and simply removed. Measured on a sandbox with a 17k-file asset container, indexing a 100-entry chunk (chunk_size=100) referencing 4 assets each: - sync: ~29ms/doc (2.9s total) - queue worker, before: ~2.0s/doc (3m20s total) - queue worker, after: ~10ms/doc (1s total) ~200x faster for the identical job, with no cross-job staleness reintroduced (covered by new tests around resetMemoizedState()). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SRyCmr5vUE71mdgXVC3KCB
edalzell
marked this pull request as ready for review
August 5, 2026 16:18
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.
Cause
Statamic::isWorker()disables in-process memoization for the entire life of a queue worker process whenever the running command isqueue:*/horizon:*, instead of just resetting that memoization between jobs. That means every single access within one job falls back to a cache-store round trip (or full disk listing) rather than reusing an already-computed value, making queued indexing dramatically slower per document than running the identical work synchronously.Closes #15118.
Approach
Store/ContainerAssetsStore/Indexare container singletons that persist for the whole worker process, so they genuinely need an explicit reset at job boundaries. Added aresetMemoizedState()method to each, invoked once per job via a newJobProcessinglistener that's only active whenStatamic::isWorker()is true (so synchronous dispatch is completely unaffected).AssetContainer/AssetContainerContentsare Blink-facade-backed, and Laravel's realqueue:workdaemon loop already clears resolved facade instances before every job it processes — so theirisWorker()gates were redundant (and actively harmful, since they disabled memoization within a job too) and were simply removed.AssetContainerContents::add()(made unnecessary by the caller always chaining->save()right after) was also removed.Real performance numbers
Measured on a sandbox app with a 17,000-file asset container, indexing a 100-entry chunk (
chunk_size100) where each entry references 4 assets:QUEUE_CONNECTION=sync)That's a ~200x speedup for the identical job, with the fixed worker now on par with (slightly faster than) sync — confirming the fix removes the bug's overhead without reintroducing cross-job staleness (covered by new tests around
resetMemoizedState()).