›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-hold
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Holdables and holders
  • Capacity and slots
  • Acquiring holds
  • Releasing and extending
  • Expiry
  • Hold state

Operations

  • Events and listeners
  • Scheduling expiry
  • Pruning history
  • Concurrency and databases

Reference

  • Configuration
  • Console commands
  • Database schema
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Holdables and holders
  • Capacity and slots
  • Acquiring holds
  • Releasing and extending
  • Expiry
  • Hold state

Operations

  • Events and listeners
  • Scheduling expiry
  • Pruning history
  • Concurrency and databases

Reference

  • Configuration
  • Console commands
  • Database schema
  • Testing
  • Troubleshooting

byrcsc/laravel-hold · 1.x

Pruning history.

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.

Running it

php artisan hold:prune --days=30
Pruned 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.

What it never deletes

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.

  • A released hold matches on released_at, which an active hold does not have.
  • An unreleased hold matches on an expires_at already behind a cutoff that is itself in the past, so a live expiry cannot qualify.
  • An indefinite hold has a null 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.

The boundary is exact

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.

Negative windows are refused

php artisan hold:prune --days=-1
The --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.

Nothing is announced

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.

How it deletes

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.

Choosing a window

The table grows by one row per acquisition and never shrinks on its own. Pick a window from what you actually query:

  • Debugging and support. 30 days covers "what happened to my booking last week".
  • Reporting. Long enough to cover your reporting period, or export before pruning.
  • Legal or audit retention. The hold row is not an audit trail. It records who released a hold and when, and nothing else. If you need attributed history, write it to your own table from a listener and prune holds freely.

What to read next

  • Scheduling expiry for the other optional command, and the one that fires events.
  • Console commands for both signatures, exit codes, and output in one table.
  • Database schema for what the table costs as it grows.
PreviousScheduling expiryNextConcurrency and databases
View source

On this page

  1. Running it
  2. What it never deletes
  3. The boundary is exact
  4. Negative windows are refused
  5. Nothing is announced
  6. How it deletes
  7. Choosing a window
  8. What to read next