Make array cache request-local and add worker-array store#406
Conversation
Document the full design for making the array cache store request-local in Hypervel while preserving the current worker-lifetime behavior as an explicit worker-array store. The plan records the Laravel reference behavior, Hypervel coroutine-context implications, storage and lock design, configuration changes, documentation updates, Reverb usage, and the required test coverage so the implementation can be reviewed against the agreed shape.
Extract shared array-store behavior into AbstractArrayStore and move ArrayStore's mutable values and lock records into CoroutineContext. ArrayStore now uses unique per-instance context keys so separate manually-created stores do not share data inside the same coroutine. The static key sequence is intentionally never reset because live context buckets may still reference earlier suffixes. ArrayLock now works through store methods instead of reaching into a public locks array, preserving lock behavior while allowing both request-local and worker-lifetime backends.
Add WorkerArrayStore for deliberate worker-lifetime in-memory cache state. CacheManager now resolves multi-word internal driver names with Str::studly(), adds createWorkerArrayDriver(), and keeps custom creators ahead of built-in drivers. The foundation cache config lists worker-array alongside array while keeping the default and failover behavior unchanged.
Update array-store tests to assert behavior instead of the removed public lock array. Add coroutine-isolation coverage for request-local ArrayStore values, locks, tags, and copied context behavior. Add WorkerArrayStore coverage for values, TTLs, serialization, counters, touch, tags, locks, flush separation, and cross-coroutine sharing. Extend CacheManager tests for worker-array construction, multi-word driver resolution, and custom creator precedence.
Reverb's Pusher server keeps a RateLimiter instance on the server object and uses it across websocket messages handled by the same worker. Switch that limiter from the request-local array store to worker-array so message counters persist for the worker lifetime as intended. Add coverage that the counter is written to worker-array, not array, and that repeated messages still trigger the configured rate-limit error.
Update tests that intentionally need cache state to survive request or coroutine boundaries. The Inertia throttle test uses worker-array because the limiter counter must survive both requests. Queue unique-after-response coverage uses worker-array because unique locks must be visible across the after-response child coroutine. Scheduler mutex tests use WorkerArrayStore because scheduling mutexes must survive across scheduler coroutines. The SubMinuteSchedulingTest setup now resolves Schedule after binding the test mutexes so the schedule receives the intended mutex implementations.
Document Hypervel's two in-memory array cache stores. The Boost cache docs now describe array as request-local / unit-of-work local and worker-array as worker-lifetime state, including coroutine context copy behavior and object-reference behavior when serialization is disabled. The cache package README records the Laravel difference and the explicit worker-array store for deliberate worker-local persistence.
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughRefactors Hypervel's ChangesArray Cache Coroutine-Local Refactor + Worker-Array Store
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR refactors
Confidence Score: 5/5Safe to merge. The coroutine isolation and worker-lifetime split is correctly implemented, tests cover the key behavioral guarantees, and no incorrect logic was found. The core design — CoroutineContext-backed ArrayStore, instance-property-backed WorkerArrayStore, Str::studly() driver dispatch in CacheManager — is straightforward and correct. Lock operations, flush separation, tagged-cache isolation, and the Reverb rate-limiter migration all check out. The static sequence counter on ArrayStore is correctly left unreset with an explanatory comment, and the test suite exercises coroutine interleaving, copied-context copy-on-write, and manager multi-word driver resolution. No files require special attention. Important Files Changed
Reviews (2): Last reviewed commit: "fix(cache): align array store touch key ..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/reverb/src/Protocols/Pusher/Server.php`:
- Line 215: The rate limiter initialization in Server::... currently
hard-depends on the named worker-array cache store, which can fail on older
published cache configs. Update the rateLimiter setup to use the cache manager’s
built-in worker-array driver directly via build(['driver' => 'worker-array']) or
add a safe fallback before constructing RateLimiter, so the code does not
require cache.stores.worker-array to exist.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4abcbf1f-f8d7-495f-8f16-b62cd9993a07
📒 Files selected for processing (19)
docs/plans/2026-06-29-array-cache-coroutine-local-worker-array.mdsrc/boost/docs/cache.mdsrc/cache/README.mdsrc/cache/src/AbstractArrayStore.phpsrc/cache/src/ArrayLock.phpsrc/cache/src/ArrayStore.phpsrc/cache/src/CacheManager.phpsrc/cache/src/WorkerArrayStore.phpsrc/foundation/config/cache.phpsrc/reverb/src/Protocols/Pusher/Server.phptests/Cache/CacheArrayStoreCoroutineIsolationTest.phptests/Cache/CacheArrayStoreTest.phptests/Cache/CacheManagerTest.phptests/Cache/CacheWorkerArrayStoreTest.phptests/Inertia/InertiaServiceProviderTest.phptests/Integration/Console/CommandSchedulingTest.phptests/Integration/Console/Scheduling/SubMinuteSchedulingTest.phptests/Integration/Queue/JobDispatchingTest.phptests/Reverb/Protocols/Pusher/ServerTest.php
Remove the redundant getPrefix() call from AbstractArrayStore::touch() so touch uses the same key path as get, put, forget, and increment. Qualify the increment read/modify/write comment so it clearly applies to WorkerArrayStore's shared worker-lifetime backing without implying the request-local ArrayStore has the same coroutine-sharing concern. This resolves the accepted Greptile feedback from PR #406 while keeping the rejected CodeRabbit Reverb fallback and docstring threshold items out of the codebase. Focused cache/Reverb tests and composer fix were green before commit.
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
Laravel's
arraycache driver is effectively request-scoped because the PHP process normally ends after each request. Hypervel workers are long-lived, so keepingarrayvalues on the store object made the public API behave differently and allowed cache data to persist across unrelated requests handled by the same worker. This PR refactorsarrayto store its mutable data in coroutine context so it behaves as request / unit-of-work local in Hypervel too. The old worker-lifetime behavior is still useful for intentional worker-local state, such as Reverb's websocket message rate limiter and tests that need mutexes or locks to survive coroutine boundaries, so it is preserved as a separateworker-arraycache driver.For more details, see:
docs/plans/2026-06-29-array-cache-coroutine-local-worker-array.mdSummary
arraycache values, locks, and tag markers coroutine-local throughCoroutineContext.worker-arrayas an explicit worker-lifetime in-memory cache store.worker-arrayso websocket message counters persist across messages in a worker.worker-arraywith comments explaining why.Details
Request-Local
arrayArrayStorenow keeps separate coroutine-context buckets for cache values and lock records. Each store instance gets unique context keys, so manually-created stores still do not share state inside the same coroutine. The buckets are plain arrays so copied coroutine context receives a starting snapshot without sharing future writes.Shared cache behavior now lives in
AbstractArrayStore, whileArrayStoreandWorkerArrayStoreonly define how items and locks are stored.ArrayLockno longer reaches into a public lock array; it uses store methods instead.Worker-Lifetime
worker-arrayWorkerArrayStorepreserves the old in-memory worker-lifetime behavior using instance properties. Persistence comes from the manager-cached repository/store, not static state, so multiple configured stores remain isolated.The foundation cache config now lists and defines
worker-arraynext toarray. The app skeleton config needs the same store entry, handled separately in the skeleton repo.Reverb And Tests
Reverb's Pusher server caches its
RateLimiteron the server object and uses it across websocket messages handled by the same worker. That counter must be worker-local rather than request-local, so it now usesworker-array.A few tests also intentionally need cache state to survive request or coroutine boundaries:
Those tests now use
worker-arrayexplicitly and include comments explaining why.Tests
touch, tags, locks, flush separation, and cross-coroutine sharing.worker-arrayconstruction, multi-word driver resolution, and custom creator precedence.composer fixsuccessfully: cs-fixer, phpstan, and the full parallel test suite are green.Review
Claude reviewed the implementation and signed off. The only post-review suggestion was adding an inline comment explaining why
ArrayStore's static context-key sequence is intentionally not reset; that has been included.Summary by CodeRabbit
New Features
worker-arraycache store for worker-lifetime in-memory caching.arraycache store now behaves as request/local coroutine-scoped storage.Bug Fixes
Documentation
arrayandworker-arraystores.