›
byrcsc/laravel-hold · 1.x
Delete released and expired hold history older than a safe retention window.
Released and expired holds stay in the table as history. This is the only command in the package that deletes anything.
php artisan hold:prune --days=30Pruned 412 holds.--days defaults to 30. The command deletes holds that were released, or
passed their expiry, more than that many days ago.
Schedule it at whatever interval suits your retention policy:
use Illuminate\Support\Facades\Schedule;
Schedule::command('hold:prune --days=90')->daily();The package registers no schedule of its own.
A live hold cannot be reached by any valid window. Two branches select prunable rows, and neither can match a hold that is still blocking a slot.
released_at, which an active hold does not have.expires_at already behind a cutoff that is
itself in the past, so a live expiry cannot qualify.expires_at, so it matches neither comparison,
however old it is.That last one is worth stating plainly: hold:prune never deletes an
indefinite hold. If indefinite holds accumulate in your application, release
them deliberately rather than expecting retention to clear them.
A hold that died exactly on the cutoff is pruned. The comparison is <=
against now()->subDays($days).
--days=0 puts the cutoff at this instant and prunes every dead hold,
including ones released a second ago. It still spares every live hold, because
the two branches above cannot reach one.
php artisan hold:prune --days=-1The --days option must be a whole number of days, zero or more.The command exits non-zero and deletes nothing.
A negative window would put the cutoff in the future, where live holds are. Both branches would then match holds that are still blocking slots, so the input is refused rather than clamped.
The same refusal covers anything that is not a whole number: 1.5, abc, an
empty string. 30 and '30' are treated identically, so a value passed from
another command behaves like one typed at a terminal.
Pruning fires no events. It is maintenance, not lifecycle. A hold deleted here was already released or expired, and whatever was going to be announced about it was announced when it happened.
If you need a record of what was removed, capture it before the run. The command reports only a count.
The command reads up to 500 primary keys, deletes those rows, and repeats until a pass deletes nothing. Each pass strictly shrinks the matching set, so the loop terminates.
Keys are read and then deleted by key rather than issuing a single
DELETE ... LIMIT, because PostgreSQL does not accept that form.
The table grows by one row per acquisition and never shrinks on its own. Pick a window from what you actually query: