How Core's cron runner works
One crontab line invokes Core's cron.php every 5 minutes. The runner walks the registered tasks, dispatches each due task to its owning module, captures status, and surfaces totals on the Overview tab.
Last updated 20 days ago
How Core's cron runner works
ImpulseCore replaces the per-module crontab clutter you usually get with WHMCS addons. One crontab line dispatches to every module's tasks. One schedule, one audit trail, one place to look when something's stuck.
The single cron line
# ImpulseCore β cron runner (every 5 minutes) */5 * * * * /usr/bin/php /path/to/whmcs/modules/addons/impulsecore/cron.php Replace /usr/bin/php with your PHP CLI binary. On Plesk: /opt/plesk/php/8.3/bin/php. On cPanel: /opt/cpanel/ea-php83/root/usr/bin/php. On a vanilla LAMP install: /usr/bin/php or whatever which php returns. Replace /path/to/whmcs with your install dir.
Whether you have one Impulse module installed or five, this is the only Core cron line you need. Every tick, the runner walks mod_impulsecore_cron_tasks and dispatches every task whose next_run_at is in the past.
What happens on each tick
- The runner queries
mod_impulsecore_cron_tasksfor rows wherenext_run_at <= NOW(). - For each due task, it dispatches to the module that registered the task β Core looks up the module's
CronHandlerclass and calls the method matching the taskname. - The runner captures the outcome β
finished,failed, orskippedβ and writes one row per task intomod_impulsecore_cron_logwith status, duration, and any error context. - It updates the task's
last_run_atand computes the nextnext_run_atfrom the registered cadence. - Failed tasks also write an audit entry under the module's slug with severity
error.
The Overview tab reads from mod_impulsecore_cron_log to render the per-task health indicators (green / amber / red) and totals.
How tasks register
"cron_tasks": [ {"name": "impulseminio_alerts", "cadence": "15min"}, {"name": "impulseminio_usage_sync", "cadence": "hourly"}, {"name": "impulseminio_audit_purge","cadence": "daily"} ] On module activation, Core inserts these into mod_impulsecore_cron_tasks with next_run_at = NOW(). The runner picks them up on the next tick. Re-activating the module is idempotent β existing rows are updated rather than duplicated.
Why this design
- One place to audit. Every dispatch is logged. You don't have to guess whether a module's cron ran; you query one table.
- One schedule to manage. Add or remove modules, the cron line never changes.
- No per-module cron drift. Operators can't accidentally leave a stale
*/2 * * * *line behind when uninstalling a module. Removing the addon removes the task row. - Heartbeats per task. Stuck tasks surface in the Overview panel before they cause customer-visible problems.
Forcing a task to run now
Stamp next_run_at = NOW() on the task row and the runner will pick it up on the next 5-minute tick:
UPDATE mod_impulsecore_cron_tasks SET next_run_at = NOW() WHERE name = 'security_collect'; Or run a task synchronously from the shell to see its full output:
/usr/bin/php /path/to/whmcs/modules/addons/impulsecore/cron.php --task=security_collect Useful after adding a new server or registering a new module's CPE β saves waiting 24 hours for the next daily tick.
The 5-minute walker timeout caveat
The cron runner expects each dispatched task to finish within the 5-minute window between ticks. Long-running tasks (multi-hour migrations, large reconciliation sweeps) can be killed if a second tick fires before the first finishes. Modules that need sustained work register a separate cron entry of their own at a different cadence β ImpulseDB Postgres, for example, ships its own impulsepostgres_provision.php line that runs every 2 minutes specifically for provisioning loops.
The Security & Maintenance pipeline always rides on Core's runner; module-side provisioning loops are the exception, not the rule.
Diagnosing missed runs
The Overview tab's Cron Health panel lists every registered task with its last-run timestamp. If every task is red, the underlying Core cron line isn't firing. Confirm with:
SELECT MAX(executed_at) FROM mod_impulsecore_cron_log; -- Should be within the last 5 minutes if cron is healthy. If the timestamp is missing or stale, debug at the system-cron level β crontab -l | grep impulsecore, check journalctl -u cron, run the script by hand as the cron user.