Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Cache Evict Laravel Package

vectorial1024/laravel-cache-evict

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm you actually need it. Laravel's cache drivers fall into two camps: those with native TTL enforcement (Redis, Memcached, DynamoDB — the store expires entries for you) and those without (the file driver, and to a lesser extent database, where expired rows linger until read). This package targets the second camp: it exists to reclaim space and keep the cache store tidy when nothing else will. If you are running Redis with a sensible maxmemory-policy, your day-to-day benefit is close to zero.

2. Install and publish.

composer require vectorial1024/laravel-cache-evict
php artisan vendor:publish --tag=cache-evict-config   # verify the tag in the README

Laravel's package discovery registers the service provider automatically; you should not need to touch config/app.php.

3. Read these three things first, in this order:

  • config/cache-evict.php (or whatever the published filename is) — this is the real documentation. Look for: enabled/disabled flag, the list of stores it operates on, the batch/scan size, and any lock or TTL thresholds.
  • The README's command section — get the exact artisan signature.
  • composer.json of the package — confirm the relaxed PHP floor from 2.1.2 matches your runtime, and check the illuminate/* constraints against your Laravel version before you commit to it.

4. First use case — wire it into the scheduler. This is the whole point of the package. In app/Console/Kernel.php (or routes/console.php on Laravel 11+):

$schedule->command('cache-evict:run')   // use the real signature from `php artisan list`
    ->hourly()
    ->withoutOverlapping();

Run it once manually first (php artisan <command> -v) against a non-production store, and compare the reported count/time against a manual inspection of storage/framework/cache/data or the cache table. If the numbers do not reconcile, stop and read the driver section of the README before scheduling anything.

5. Keep the default driver during adoption. Switch it on for a single non-critical store, let it run for a week, then widen the scope. There is no reason to enable it globally on day one.

Implementation Patterns

Scheduler-driven housekeeping (the default pattern). Treat the package as a cron job, not a request-path concern. withoutOverlapping() and, on multi-node deployments, onOneServer() are mandatory — a scan that races itself doubles the I/O and can produce misleading counts. Suggested cadence: hourly for high-churn file stores, daily for low-churn ones. There is no value in running it more often than your shortest meaningful TTL.

Tier the schedule by store. If you have several stores configured, do not run them all on the same cron tick. Stagger them, or invoke with a per-store flag if the command supports one, so a slow file sweep does not collide with a database sweep on the same worker.

Complementing, not replacing, Laravel's built-ins. Laravel ships cache:prune-stale-tags for tag-index cleanup. These solve different problems: stale tags are metadata, this package is about expired payloads. Run both in the scheduler, in separate slots. Do not assume one covers the other.

Multi-tenant / per-tenant cache scoping. If you prefix cache keys per tenant, the package will sweep whatever the configured store exposes. Decide deliberately whether eviction is global or tenant-scoped, and if the package offers no tenant filter, do not try to bolt one on with key-prefix hacks in config — write a thin wrapper command that resolves the store for each tenant and calls the underlying service.

Observability wrapper. The command's exit code and output are your signal. Rather than trusting the scheduler's silent log, wrap it:

$schedule->command('cache-evict:run')
    ->hourly()
    ->withoutOverlapping()
    ->onOneServer()
    ->then(fn () => Cache::increment('cache_evict_runs'))
    ->onFailure(fn () => Log::error('cache-evict failed'));

Alert on repeated failures or on a sudden drop in evicted-entry counts — a count collapsing to zero usually means the config was cached with the feature disabled, or the store path changed under you.

Deployment and config caching. Because this is config-driven, remember php artisan config:cache freezes the published config at deploy time. Any change to enabled stores must go through a deploy, not a live edit. Add the eviction cadence to your deploy checklist rather than expecting developers to remember it.

Testing. In feature tests, bind the package's config to a disabled state (or point it at the array driver) so test runs never touch a real store. If the package exposes a service you can resolve from the container, mock that instead of invoking the command — command-level tests will be slow and driver-dependent.

Gotchas and Tips

Driver semantics are the main source of confusion. Eviction is only meaningful on stores that do not self-expire. On Redis or Memcached you are largely duplicating work the store already does; on file you are genuinely useful; on database you need to know whether the package deletes rows, updates them, or relies on Laravel's own expiration column handling. Read the README's driver table before enabling a store, and verify by inspecting the storage backend before and after a run rather than trusting the output count.

Entries without a TTL are forever. Anything cached with Cache::forever() has no expiry and, by definition, is not "expired" — a correct implementation will leave it alone. If disk usage keeps climbing after you enable the package, look for forever() calls and unbounded key growth first; the package cannot fix a design problem.

The relaxed PHP floor in 2.1.2 is a graph-wide claim, not a package-local one. Before bumping, re-run CI on your oldest supported PHP image and check that no transitive dependency still pins a stricter php constraint. A relaxation that Composer cannot actually resolve buys you nothing.

Locking and overlap are your responsibility. Most eviction packages do not ship their own lock. Without withoutOverlapping(), a long sweep plus a short schedule interval equals concurrent scans, doubled I/O, and confusing log lines. On multi-server setups, onOneServer() additionally requires a shared cache/atomic lock driver — if your default lock store is file, onOneServer silently degrades.

Clock skew and long-lived workers. Freshness decisions depend on now(). Queue workers with long timeouts and servers with unsynchronised clocks will produce off-by-minutes eviction. Keep NTP in place, and avoid running the sweep from a worker that has been alive across a DST transition.

File-driver permissions and path drift. The file driver resolves paths from config('cache.stores.file.path'), typically storage/framework/cache/data. If your deploy creates a fresh release directory and symlinks storage, verify the sweep runs as the same user that wrote the files, and that the path is the symlinked one. Permission errors here surface as a silent zero-eviction count, not an exception.

Shared/remote stores need a blast-radius review. Pointing this at a shared Redis instance or a cache cluster serving multiple applications is risky: deletion is not scoped to your app unless your key prefix is. Confirm prefix isolation before enabling, and prefer a dedicated store.

Config cache is the classic "it stopped working" cause. If evictions stop after a deploy, first check bootstrap/cache/config.php for a stale copy of the published config, and confirm the feature's enabled flag is truthy there. This accounts for most "the package is broken" reports on config-driven Laravel packages.

Extension points to look for before forking. Most packages in this space expose at least one of: a bound service/interface, an event fired per eviction batch, or a configurable driver list. Hook there — an event listener for logging and metrics is far cheaper to maintain than a copied-and-patched command. If no extension point exists, wrap the call in your own command and let the package's command remain untouched.

Version pinning. With a terse release history, pin to a caret range you have tested (^2.1) and read CHANGELOG.md on every bump. Given the low release volume, treat each version as worth a CI run rather than assuming patch-level safety.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console