hyperf/model-cache
Hyperf model-cache adds automatic caching for Hyperf ORM models, reducing repeated database queries and speeding up reads. It integrates with model events for cache invalidation and supports configurable TTL and cache stores.
Architecture fit. The headline for a Laravel estate: this is not a Laravel package. hyperf/model-cache is a component of the Hyperf 3.x framework (Swoole/Swow coroutine runtime) and hard-depends on hyperf/database, hyperf/di, hyperf/event, hyperf/cache and hyperf/redis. It cannot be pulled into a Laravel app. That reframes the decision from "adopt a library" to "is the target service on Hyperf at all?" For Laravel services, the correct use of this artifact is as a reference architecture and design blueprint for the Laravel equivalent (geneaLabs/laravel-model-cache or hand-rolled observers), which maps close to 1:1 onto the same patterns.
Where the stack is Hyperf, the fit is good: a Cacheable trait plus a config map, no ORM fork, and two clean extension seams (HandlerInterface for Redis/Array handlers, and the per-model config map for TTL/keying). Explicit findFromCache() / findFromCacheMany() rather than magic interception of find() means adoption is incremental and reversible at the call-site level.
Integration feasibility. Technically straightforward on Hyperf — a composer require, a published config, a trait on the model, and wrapping hot read sites in repository methods. The real cost is not installation, it is the write-path audit: builder-level updates, increment()/decrement(), upsert(), and raw DB::update() fire no model events, so nothing invalidates. Every mutation that must be visible quickly has to be routed through hydrated models or explicitly invalidated. That survey is where engineering days actually go.
Technical risk.
findFromCache() hydrates from cached attributes and does not run global scopes; a missed delete event keeps serving a deleted row.Key questions.
use_redis_cluster match actual topology (Lua script routing causes CROSSSLOT/NOSCRIPT under load)?Stack fit — gate first. On Hyperf 3.x → proceed to a scoped pilot. On Laravel/Symfony/plain PHP → do not integrate; select the idiomatic equivalent and use this package's patterns (event-driven invalidation, tag-based clearing, negative caching, handler swap for tests) as the acceptance criteria for that choice. A Laravel→Hyperf migration is a framework programme and should never be justified by a caching library.
Compatibility notes to validate in the spike. Single-column primary keys only (composite keys unsupported; UUID strings are fine). Redis is the realistic backend; the array handler is test-only. Hyperf's AOP compiles proxies into runtime/container/proxy — stale bytecode produces false "the trait doesn't work" results, so add a container-clear step to the runbook. Two distinct CacheableInterface classes exist (Hyperf\Cache\* vs Hyperf\ModelCache\*); confirm imports before debugging anything else.
Migration path (parallel run, no big bang).
findFromCache() / findFromCacheMany() — batch reads for list endpoints, never a loop of single lookups.config/autoload/model_cache.php: env- and service-scoped prefix, per-model TTL and cache_key, and a deliberate empty_model_ttl decision (non-zero on public endpoints to blunt id-scanning; zero where "created a second ago" must be visible).MODEL_CACHE_ENABLE=false, then enable per model via the config map — the kill switch is the one-line rollback and the first diagnostic step for any "cache bug".findFromCacheMany after deploys or prefix flushes, converting a cold-cache stampede into a predictable backfill.Sequencing. Pilot on one feature, one quarter. Content/catalogue/dashboard reads first — high read amplification, tolerance measured in minutes. Explicitly exclude checkout, balances, ledgers, and permission material. Broaden model coverage only after a clean month of hit-rate and stale-incident data. Version the key namespace segment on any structural model change (casts, hidden fields, relations) rather than flushing production.
Testing. Bind ArrayHandler in the test container so CI never touches Redis; keep RedisHandler in staging so the Lua atomicity paths are actually exercised.
Maintenance. Low and routine. v3.2.3 is a bare changelog pointer for v3.2.0→v3.2.3 — patch-level, no stated breaking changes, deprecations, or migration steps. Pin ^3.2, let the changelog diff run in CI, and schedule upgrades as normal dependency hygiene. It is a maintenance signal (project alive and patching), not a roadmap signal.
Support. MIT, under the Hyperf organisation, actively released — but a small ecosystem with thin secondary documentation. Practical implication: name an internal owner, write the runbook ourselves, and don't assume community answers. The two safe extension points are the handler layer and the per-model config map; custom keying, metrics, or a versioned invalidation scheme should live there rather than in a fork of the trait.
Scaling. The package removes database pressure and adds a hard Redis dependency to the read path. Size Redis for the hot key set plus negative-cache entries; verify cluster routing against load_script; use findFromCacheMany so list endpoints do one mget rather than N round trips. Multi-service or multi-tenant shared Redis with a default prefix is a self-inflicted outage — namespace app + env + service into prefix.
Failure modes and runbook.
TTL/GET the specific mc:* key → is the key wrong, or did invalidation never fire → inspect the write path for a bypass → check empty_model_ttl before concluding the cache is broken.find() behaviour explicitly rather than assuming it.MODEL_CACHE_ENABLE=false converts findFromCache to find(); if the bug vanishes, the read path is fine and invalidation is at fault. This is the fastest triage lever we have.Ramp-up. Half a day for a competent Hyperf engineer to wire the pilot; the durable cost is cultural — the team must treat invalidation as a contract, mutate through hydrated models by default, and audit every delete/restore path. Budget for a short internal enablement session on coroutine/AOP-proxy quirks.
Success criteria and governance. Success = measurable database load reduction on the pilot endpoints with zero stale-data incidents in the first 30 days, and a documented per-model staleness budget agreed with product. Governance artefacts: an explicit deny-list (money, stock, auth), a per-model TTL policy, and a one-env-var rollback path. For stakeholders outside engineering, the pitch is a reversible configuration-level optimisation that buys one or two quarters of read headroom — with the caveat stated plainly that the package under review is Hyperf-only, so a Laravel estate should adopt the equivalent library against these same criteria.
How can I help you explore Laravel packages today?