sanchescom/laravel-cache-memory
Architecture fit. sanchescom/laravel-cache-memory is a cache store backed by a host-local shared-memory segment, exposed through the standard Laravel Cache contract. Release 2.1.0 materially changes what it is for: prior to this version it was a fast-but-approximate store (non-atomic add() with TTL was emulated with get() + put()); it is now a correct single-host coordination primitive. Atomic add() (semaphore-guarded, false on live entry, verified by a 16-process × 50-key × 6-round fork test) plus a real LockProvider (Cache::lock() with owner-checked releaseLock() in one critical section, verified by 16 processes × 20 non-atomic RMWs landing on exactly 320) means the package can host idempotency keys, rate limiters, "first writer wins" elections, and mutexes — not just read-through caching. The architectural constraint is unchanged and absolute: coordination is per-host, per-segment. It is a fit for single-node apps, php-fpm workers on one box, CLI/batch jobs that must serialize against each other, and test suites; it is not a fit for any horizontally scaled, multi-node, or multi-tenant-by-node topology where Redis/DB would be the correct answer.
Integration feasibility. Low effort, high leverage. It is a drop-in store driver: composer require, register the store in config/cache.php, point the relevant cache at it. The 2.1.0 additions require no new application code to take effect — Cache::add() with TTL becomes atomic for free on this driver with return semantics unchanged, and Cache::lock() begins working wherever the store is used as the lock backend. The interesting integration surface is therefore not "can we install it" but "which code paths should now point at it," which is a config-and-ownership question, not an engineering one.
Technical risk.
flush(), requestDeletion(), and the overflow path discard held locks along with the data. Any code that flushes the store — deploy hooks, cache-clear endpoints, test teardown, an overflow — silently releases mutexes other processes believe they hold. This is the same semantic as every Laravel cache-backed lock, but on a small fixed-size segment, overflow is a realistic trigger, not a theoretical one.E_USER_WARNING; 2.1.0 correctly makes add() return false so MemoryLock::acquire() cannot report a lock it does not hold even when the warning is masked. That is the right fix, but it converts an availability problem into a correctness-preserving failure — work still stops.refresh() is unsupported. Any job that extends a lock's TTL mid-flight (long-running imports, queue workers, report generation) will behave differently here than on Redis. This needs a code audit, not an assumption.stats() and memory:stats now give visibility (segment key, usable capacity, bytes used/free, item count, expired count, read under the lock without purging) — but they are observability, not autoscaling.Key questions.
Cache::flush() / cache:clear against this store, and what holds locks at those moments?refresh()? Which jobs, and what is their max runtime versus lock TTL?Stack fit. Best fit: single-host Laravel deployments with php-fpm plus CLI workers sharing one machine, where the alternative is installing/maintaining Redis purely for locking and rate limiting. Also a strong fit for test suites and CI, where per-process isolation and memory:stats make contention behavior inspectable. Poor fit: multi-node clusters, serverless/ephemeral containers, anything where a lock must be visible across hosts.
Migration path. Two independent tracks:
composer update sanchescom/laravel-cache-memory. No breaking changes per the release notes and UPGRADE.md. Verify the existing store config still boots and that add()-with-TTL callers tolerate the now-genuinely-atomic semantics (they should — return semantics are unchanged) and the new false on overflow-discarded writes.Cache::lock() consumers from the default lock driver to this store, and route idempotency keys through Cache::add(). This is a behavioral change for the application even though it is not a change to the package's API, so it needs its own rollout.Compatibility. Confirm the Laravel and PHP versions in use are supported by 2.1.0, and confirm extension availability in every runtime image. Explicitly document the known deltas versus other drivers in an internal note: refresh() unsupported; locks share the key space with cache entries; flush() and overflow release locks.
Sequencing.
memory:stats output, and segment key/capacity settings.memory:stats (or call stats()) into existing monitoring so used/free bytes, item count, and expired count are visible before load changes.add() first — lowest risk, no API change, immediate correctness win for idempotency keys and rate limiting.Cache::lock() on one low-blast-radius path with a short critical section (a scheduled command, a single job type), with a contention test.refresh() usage and flush()-during-lock-hold before widening lock adoption.Maintenance. Small, focused dependency with a credible correctness story (forked contention tests for both add() and lock mutual exclusion are exactly the evidence a TPM wants). The maintenance burden shifts to us in two places: segment capacity sizing, and keeping the lock-vs-cache key namespace discipline. Both are config and code-review items, not ongoing engineering. Pin the version and review changelogs on release; the 2.1.0 note that add() returns false on overflow is the kind of subtle semantic change worth reading for every time.
Support. No vendor support; community package. Internal ownership should sit with whoever owns the cache/queue infrastructure. Because the failure modes are host-local, debugging is straightforward — memory:stats gives a direct read on capacity pressure without purging, which is a genuine support improvement over 2.0.0. Escalation path is "read the segment stats, check for overflow warnings, check for flush events," which is a short runbook.
Scaling. Strictly vertical and per-host. Throughput scales with cores and segment size on a single box; it does not scale out at all, and it does not degrade gracefully — it hits a capacity wall (overflow, store emptied, warning raised). Growth plan must be explicit: when the app needs a second node, the locking layer must move to Redis/DB before the second node lands, not after. Locking correctness and horizontal scaling are mutually exclusive here.
Failure modes.
E_USER_WARNING, add() returns false, locks released, cache cold. Correct-by-design in 2.1.0 (no phantom locks) but user-visible as a thundering herd plus lost mutexes. Primary mitigation: capacity headroom plus alerting on used/free.flush() / requestDeletion() during a held lock → silent mutex loss. Mitigation: forbid blanket flushes on this store; scope clears by key.releaseLock() in a single critical section. This is the release's most valuable operational property; it removes a class of double-release corruption.refresh() → lock expires mid-job, concurrent execution. Mitigation: audit and cap job runtime below lock TTL.Ramp-up. Low for developers — it is the standard Cache facade, and Cache::lock() now "just works," so there is little new API to learn. The ramp-up that matters is conceptual and should be a short written note in the team's docs: this store is per-host; locks share the key space with data; overflow and flush release locks; refresh() is unsupported; check memory:stats before debugging. Roughly a half-day of onboarding plus the refresh() audit. The most likely adoption mistake is treating this as a Redis substitute rather than as a single-host coordination primitive.
How can I help you explore Laravel packages today?