Scheduled Tasks
jekcms runs background work through a lightweight task scheduler stored in the scheduled_tasks DB table. Each row is a named job with an interval, a PHP callable, and a last_run_at timestamp. A single entry point — cron.php — walks the table every minute and fires anything that's due.
This page covers how it works, what runs by default, how to add custom tasks, and how to set up cron on your host.
How jekcms runs scheduled tasks
The preferred path is an OS-level cron job that hits cron.php once a minute. On every tick the scheduler:
- Acquires a lock file at
storage/locks/cron.lock(prevents overlapping runs) - Selects all tasks where
NOW() >= last_run_at + interval_seconds - Runs each callable, captures stdout and exceptions, writes a row to
scheduled_task_runs - Updates
last_run_atandlast_statuson the parent task
On shared hosts without real cron, jekcms falls back to a sparse web-request tick: roughly 2% of front-end page requests invoke a tiny shim that runs one due task and returns. Low-traffic sites limp along this way, but the recommendation is always: install real cron if you can.
Built-in tasks
Every install ships with these rows already populated:
post.scheduled_publish— every 1 min. Promotes posts whosepublish_atis in the past fromscheduledtopublished, fires thepost.publishedwebhookai.bulk_worker— every 1 min. Pulls the next pending item off the AI bulk generation queue and runs it (respecting per-batch rate limit)license.heartbeat— every 6 h. Pings the jekcms license server, rotates the local license cache tokenupdates.check— every 6 h. Calls the update manifest endpoint, populates the Update available bannerbackup.rotate— daily at 03:00. Keeps the five newest pre-update backups, deletes older onessitemap.refresh— every 30 min. Rebuildssitemap.xml+ per-type shards ifposts.updated_atchanged since last build
You cannot delete built-in tasks, but you can disable any of them from the admin UI at admin/scheduled-tasks.php.
Creating a custom task
Go to Automation → Scheduled Tasks → New task. Fill in:
- Name: unique slug, e.g.,
myplugin.daily_digest - Interval: seconds between runs (e.g.,
3600for hourly) - Callable: any PHP callable reachable from the bootstrap scope, e.g.,
MyPlugin\Jobs\DailyDigest::run - Enabled: on/off
The callable receives one argument — the task row — and should return a short string used as last_status (e.g., "ok: 42 items").
namespace MyPlugin\Jobs;
class DailyDigest {
public static function run(array $task): string {
$rows = DB::query('SELECT id FROM posts WHERE created_at > NOW() - INTERVAL 1 DAY')->all();
Mailer::sendDigest($rows);
return 'ok: ' . count($rows) . ' posts';
}
}
Viewing execution history
Each task row has a History button that opens the last 100 runs with start time, duration, status, and captured stdout/exception. Failed runs are highlighted red. Use this to debug "my task isn't firing" — first thing to check is whether it ran at all.
Failure retry
If a callable throws, the scheduler records the exception and schedules a retry with exponential backoff: 1 min, 5 min, 15 min, 1 h. After four consecutive failures the task is marked degraded and paused — you'll see an alert in the admin dashboard. Re-enable manually once you've fixed the underlying cause.
Setting up cron
cPanel
Advanced → Cron Jobs → Add New Cron Job:
- Schedule:
/5(every 5 min) or(every 1 min) - Command:
*/5 * * * * /usr/bin/php /path/to/cron.php >/dev/null 2>&1
Replace /path/to/ with your install root. Some cPanel hosts require the full PHP binary path — which php on the shell, or try /usr/local/bin/php if /usr/bin/php isn't found.
Plain Linux (crontab)
crontab -e
Add:
* * * * * cd /var/www/jekcms && /usr/bin/php cron.php >> storage/logs/cron.log 2>&1
Windows Task Scheduler
Create a basic task → trigger daily, repeat every 1 minute, duration 24 hours → action: start C:\xampp\php\php.exe with argument C:\xampp\htdocs\jekcms\cron.php.
Verifying cron is actually running
Open any scheduled task in the admin UI and look at last_run_at. If it's within the expected interval, cron is alive. If it's stuck or empty, check:
- Is the cron job installed?
crontab -l - Is the PHP binary path correct?
- Any error output? Redirect to a log file (drop the
>/dev/null) and read it - File permissions on
storage/locks/— the web user needs write access