The Purge Job: one schedule for all cleanup
An instance that renders all day accumulates. History records with their PDFs, print tasks that have long been printed, mail tasks whose mails arrived weeks ago, and files on the history disk that no record points at any more. Cleaning that up used to be four separate nightly jobs, configured in the .env file and scheduled in code, at four fixed times nobody could change without a deployment.
The Purge Job is those four in one schedule, plus the scheduler's own run log. One cron expression, one run, five retentions.
scheduler.purge-form.pngThe purge settings with one retention field per entity and the switch that turns a step off.
The five steps
| Step | Deletes |
|---|---|
| 1. Print Tasks | Print tasks past the retention that have reached status Printed. One that never printed stays, so a problem does not disappear before anybody looked at it. |
| 2. Mail Tasks | Mail tasks past the retention, whatever their status. The mail itself is long gone, the record is the receipt. |
| 3. History Records | History records past the retention, together with their PDF and their xlsx export. |
| 4. Orphaned Files | Files on the history disk that no history record and no mail task refers to any more, and that are older than the retention. |
| 5. Scheduler Run Log | The run records of the Job Scheduler itself. The run doing the deleting never deletes itself. |
Saying how long
Every step has its own retention in days, and every step can be switched off on its own.
| Value | Means |
|---|---|
90 |
Delete what is older than 90 days. |
0 |
Delete everything older than right now. Useful for a one-off clear-out, dangerous as a standing setting. |
| switched off | That entity is never purged. The step is named under skipped in the run result, so the log shows it was a decision and not an accident. |
A sensible starting point keeps print and mail tasks shorter than the history records they belong to, and the orphaned files shortest of all. Something like 30, 30, 90, 7 and 90 days.
Where it comes from
php artisan setup:base creates the schedule as Purge Job, deactivated and without a cron expression, with the retentions taken from the .env keys the old jobs used. From then on the retentions live on the schedule and the .env keys are not read again.
Nothing is cleaned up until you give the schedule an expression and switch it on. That is deliberate: a fresh instance should not start deleting on a schedule nobody chose.
0 3 * * * every night at 03:00
0 3 * * 0 Sunday nights only, for an instance with little traffic
Who may switch a step on
A Purge Job has no owner. It runs without any user at all, which means the usual permission check has nothing to check against. So the check moves to the moment a step is configured: whoever switches a step on, or changes its retention, has to hold the permission to delete what that step deletes.
| Step | Needs |
|---|---|
| Print Tasks | report-print-task:delete |
| Mail Tasks | report-mail-task:delete |
| History Records, Orphaned Files | report-history-record:delete |
| Scheduler Run Log | scheduled-job:delete |
Steps you leave untouched are not asked about again, so somebody may change the cron expression without holding every delete permission in the instance.
What a run tells you
The run record carries the numbers per step: how many records were eligible, how many were deleted, how many could not be. A step that throws does not stop the ones after it.
| Outcome | Status |
|---|---|
| Every configured step finished | Success |
| Some steps finished, one failed or left records behind | Warning, with the reason in the result |
| Every configured step failed | Error, and the failure mail goes out |
A history record that could not be deleted because something still references it is logged individually, not swallowed into a count.
Doing it by hand
The four commands are still there, unchanged, for a one-off cleanup or for a maintenance window.
php artisan report-print-tasks:purge --days=30
php artisan report-mail-tasks:purge --days=30
php artisan report-history-records:purge --days=90
php artisan orphaned-files:purge --days=7
Run them in that order for the same reason the schedule does.
If the schedule is gone
The Purge Job is an ordinary schedule and can be deleted like any other. Nothing then cleans up, and the disk keeps filling. The Job Scheduler overview shows a warning for as long as no active purge schedule exists.
There are two ways back, and neither of them is special.
From the frontend. New on the Job Scheduler overview offers Purge Job next to Render Job. Pick it, set the retentions, give it a cron expression and switch it on. A purge schedule is created like any other schedule; it needs no owner and no API token, only a name that is still free and the delete permissions of the steps you switch on. The same way you would create a second one, for instance a weekly run with longer retentions next to a nightly one.
From the command line, for an instance you would rather not click through:
php artisan scheduler:create-purge-job
It creates the schedule under its original name when it is missing and does nothing when it is already there. Unlike setup:base it touches neither storage nor users, so it is safe on a live system. Afterwards give it its cron expression and switch it on again.