Task Management Hooks
The eight hooks where an operator reaches into scheduled work by hand: running a task, switching one off, cleaning the queue and the kill switch.
Overview
Unlike the hooks in the previous article these fire from the panel: an operator is there and reads your message.
Two of them weigh heavily. The kill switch turns every automation off, and the queue cleanup deletes history so you can no longer see what ran when.
Reference
Following a run by hand
Runs after an operator triggered a task by hand. The task is on the queue at this point, not running yet.
Hook::add('action:cron.task_run_now', 10, function ($task, $job_id) {
// The job JOINED the queue and has not run: watch job.processed for the outcome.
Audit::manualRun($task, (int) $job_id);
});Following a task switched on or off
Runs after a single task was switched on or off.
Hook::add('action:cron.task_status_changed', 10, function ($task, $enabled) {
// A task switched off stops quietly: record the critical ones.
if (!$enabled && Acme::criticalTask($task)) Ops::alert('task-off', $task);
});Blocking the kill switch
Runs before all automation is switched off. This hook fires on the off direction only.
Hook::add('gate:cron.kill_switch_disable', 10, function ($enabled, $pending_count) {
// Switching off with many jobs waiting only grows the backlog.
if ($pending_count > 500)
return 'Too many jobs are waiting; let the queue drain first.';
return null;
});Stopping a queue cleanup
Runs before the queue history is deleted. The retention days are separate per status.
Hook::add('gate:cron.cleanup_run', 10,
function ($completed_days, $cancelled_days, $failed_days) {
// Deleting failures early destroys the evidence of a problem.
if ($failed_days < 30) return 'Failed records want keeping for 30 days.';
return null;
});Following what a cleanup removed
Runs after the queue cleanup finished.
Hook::add('action:cron.queue_cleaned', 10, function ($deleted, $breakdown) {
// Many failed records removed means a problem's trace has gone.
if ((int) ($breakdown['failed'] ?? 0) > 100)
Ops::warn('cron-failures-purged', (int) $breakdown['failed']);
});Following a job intervention
Runs after an operator reached into a queued job by hand.
retry, cancel, force_reclaim, delete. The four differ greatly; do not react without reading which.cron, module, notification. There are three queues and all pass this hook.Hook::add('action:cron.job_intervened', 10, function ($action, $queue, $id) {
// force_reclaim takes a stuck job back, which means it runs again.
if ($action === 'force_reclaim') Ops::note('job-reclaimed', $queue, (int) $id);
});Catching a return after downtime
Runs where the system noticed the tasks had not run for a long while.
gap_hours, gap_seconds, last_seen. A long gap means the renewals, suspensions and invoices of that period are late.Hook::add('action:cron.restore.detected', 10, function ($restoreInfo, $workerId) {
// Renewals and suspensions are late across the gap: check the backlog.
Ops::alert('cron-gap', (float) ($restoreInfo['gap_hours'] ?? 0));
});Changing the task list
Runs before the task overview is shown in the panel.
Hook::add('filter:cron.task_overview', 10, function (&$tasks) {
// Adding to the list does NOT run a task; registration is register:cronjobs.
$tasks = array_filter($tasks, fn ($t) => !Acme::hidden($t['key'] ?? ''));
});Pitfalls
The manual trigger hook hands you a queue id: the job joined the queue and has not run. Waiting for an outcome here is pointless; what the job actually did is told by the processed hook.
The cleanup also removes failed records, and those are the only trace of a problem. Shortening retention leaves tomorrow's "why did it not run?" unanswerable. Guard the failed retention at the gate.
Retrying, cancelling, reclaiming and deleting pass one hook and their outcomes are opposites. A listener written without reading the kind can take a cancelled job for a restarted one. There are also three queues; the second parameter says which you are in.
The task list filter changes what shows in the panel and nothing more. Your own task does not run for being added there; it wants making known through the registration hook. Mixing the two leaves a card that sits in the panel and never runs.
Related Articles
- Cron Tick Hooks
- Scheduled Task Hooks
- Hooks in the Management Panel
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.