Skip to content

Scheduler

Oleg Ivanchenko edited this page Oct 18, 2026 · 2 revisions

Scheduler

oCMS includes a built-in cron scheduler that manages periodic tasks across the core system and modules. The scheduler admin UI provides a centralized interface to view, manage, and manually trigger scheduled jobs.

Overview

The scheduler manages three types of jobs:

  • Core jobs — Built-in system tasks (e.g., publishing scheduled pages)
  • Module jobs — Tasks registered by installed modules (e.g., analytics reporting, data cleanup)
  • Custom tasks — Scheduled HTTP GET requests that administrators create in the admin UI (see Custom Tasks)

Built-in jobs:

Source Name Default schedule Description
core scheduled_pages * * * * * (every minute) Publish pages scheduled for publishing
core demo_reset 0 1 * * * (daily at 01:00 server time, UTC on Fly.io) Only in demo mode: reset the demo data and restart; no manual trigger
task cleanup 0 3 * * * (daily at 03:00 server time) Delete custom-task runs older than 30 days

Each job has:

  • A default schedule (cron expression)
  • An optional override schedule (persisted to database)
  • Timing information (last run, next run)
  • Optional manual trigger capability

Viewing Jobs

Navigate to /admin/scheduler (admin only) to view all scheduled jobs:

Column Description
Job Job description and internal name
Source Origin (core or module name)
Schedule Current cron expression (or override)
Last Run When the job last executed
Next Run When the job will execute next
Actions Edit, reset, or trigger buttons

The Source column uses color-coded badges:

  • Indigo — Core system job
  • Green — Custom task (task)
  • Cyan — Module job

Editing Job Schedules

Click the Edit button to change a job's cron schedule:

  1. A modal dialog appears with the job name and current schedule
  2. Enter a new cron expression
  3. Click Save — The new schedule takes effect immediately

The system validates the cron expression before applying it. An invalid expression is rejected and the current schedule stays in place.

Cron Expression Format

oCMS uses standard cron syntax with support for shorthand intervals:

Expression Meaning
* * * * * Every minute
0 * * * * Every hour at :00
0 1 * * * Daily at 01:00
0 1 * * 0 Weekly (Sundays at 01:00)
0 0 1 * * Monthly (1st of each month)
@every 1h Every 1 hour (interval)
@every 6h Every 6 hours (interval)
@every 30m Every 30 minutes (interval)

5-Field Cron Fields:

  1. Minute (0-59)
  2. Hour (0-23)
  3. Day of Month (1-31)
  4. Month (1-12)
  5. Day of Week (0-6, 0=Sunday)

Use * to match any value in a field.

Examples

  • Publish scheduled pages every 5 minutes: */5 * * * *
  • Run analytics export daily at 2:00 AM: 0 2 * * *
  • Sync data every Sunday at noon: 0 12 * * 0
  • Cleanup old logs every 6 hours: @every 6h

Manually Triggering Jobs

If a job supports manual triggers, a Run Now button appears. Click it to execute the job immediately (outside its normal schedule).

Manual triggers:

  • Execute immediately, bypassing the cron schedule
  • Log the trigger event with the user who initiated it
  • Do not reset the job's schedule or timing counters

Not all jobs support manual triggers. Jobs that require specific timing conditions may not allow manual execution.

Resetting to Default Schedule

If a job's schedule is overridden, a Reset button appears. Click it to:

  1. Remove the override from the database
  2. Restore the default schedule immediately
  3. Update the cron job with the default timing

Schedule Overrides

When you edit a job's schedule, the override is persisted to the database:

  • Overrides survive application restarts
  • Each job has at most one override
  • Overrides are deleted when the schedule is reset
  • On startup, the scheduler loads and applies all overrides automatically

Custom Tasks

The Custom Tasks section lets administrators schedule an HTTP GET request to a URL (New Task). A task has a name (3-100 characters), a URL (at most 2048 characters; https only when OCMS_REQUIRE_HTTPS_OUTBOUND is on, the default in production), a cron or @every schedule, and a timeout of 1-300 seconds (default 30).

Each task can be edited, enabled or disabled, run immediately (one manual run per 10 seconds per task), deleted together with its run history, and its runs inspected (status, HTTP status code, duration, error). Active tasks also appear in the jobs table with source task.

  • URLs that resolve to private, loopback, link-local or other reserved addresses, localhost and cloud metadata hosts are rejected when the task is saved, before every run, and on every redirect.
  • The response body is not stored; a run records only the content type and byte count.
  • Runs older than 30 days are deleted daily by the task:cleanup job.

Demo Mode Restrictions

When demo mode is enabled (see Module: Demo Mode), scheduler modifications are disabled:

  • View all jobs and schedules
  • Cannot edit job schedules
  • Cannot reset schedules
  • Cannot trigger jobs manually
  • Cannot create, edit, enable/disable, delete or run custom tasks

Audit Logging

Scheduler events are logged in the audit trail at /admin/events:

  • Schedule updated — Job's cron expression changed
  • Schedule reset — Override removed
  • Job manually triggered — Job executed manually
  • Scheduled task created / updated / enabled / disabled / deleted / manually triggered — Custom task changes

Each event includes the user, job source/name, new schedule, client IP, and request URL.

Common Use Cases

Check for Scheduled Pages Less Often

Pages scheduled for publishing are picked up every minute by default. If that is more than you need:

Default: * * * * * (every minute) Override: */5 * * * * (every 5 minutes)

Disable a Job

Set its schedule to an impossible expression:

0 0 31 2 *

(February 31 doesn't exist). For a custom task, use Disable instead.

Shift Job Timing

Move a job away from your backup window:

Current: 0 2 * * * (daily at 2:00 AM) Override: 0 4 * * * (daily at 4:00 AM)

Troubleshooting

Job Never Runs

  1. Check the cron expression is valid
  2. Verify the job's source module is active (for module jobs)
  3. Ensure the application is running (jobs run in-process)
  4. Check application logs for execution errors

Manual Trigger Returns Error

  • Job may not support manual triggers
  • Check application logs for the specific error
  • Verify the job's source module is loaded

Override Not Persisting

  1. Verify database write permissions
  2. Check application logs for database errors
  3. Restart the application to re-apply overrides

Clone this wiki locally