02.07 The Cron Jobs
Reference catalog of the 11 cron scripts under simplerisk/cron/ — what each does, when to schedule it, which Extras it depends on, and the long-running worker scripts that run continuously rather than on a recurring schedule.
Why this matters
SimpleRisk's cron jobs are how scheduled work happens — notifications get sent, vulnerability scanners get polled, backups get taken, temporary files get cleaned up. Without the cron jobs running, the operational behavior the program depends on goes silent. Notifications stop firing. Auto-initiated audits don't get created. Vulnerability data stops syncing. Backups don't happen. Each cron is small individually; together they're the program's heartbeat.
The honest scope to know: SimpleRisk doesn't run cron jobs internally. The application doesn't have a built-in scheduler that fires the cron scripts; the OS-level scheduler on the supported Linux host (Linux cron, systemd timers, Kubernetes CronJob, whatever your environment uses) is what invokes the SimpleRisk cron PHP scripts on schedule. If you don't configure OS-level cron after the install, none of the scheduled work happens.
The other thing worth knowing: the cron scripts split into two categories:
- Recurring scripts (most of them) — invoked on a schedule (every few minutes, hourly, daily) and exit when the work is done. Standard cron pattern.
- Long-running worker scripts (
cron_promise_worker.php,cron_queue_loader.php,cron_queue_worker.php) — run for up to 60 minutes per invocation, continuously processing async work from a queue. These are intended to be invoked via cron but stay alive much longer than a typical cron script. The pattern is "start them frequently, but they self-terminate after their max runtime so the next cron invocation picks up a fresh process."
This article catalogs each cron script with its purpose, recommended schedule, and any Extra dependency.
Reference content
The orchestrator: cron.php
simplerisk/cron/cron.php is the master orchestrator. It loads the JobRunner library and executes all scheduled cron jobs from get_cron_jobs(). On each run, it:
- Logs the start via
write_debug_log(). - Updates the
cron_last_runsetting to the current Unix timestamp. - Iterates the registered cron jobs and runs each that's due.
For installations that want a single cron entry rather than per-script entries, cron.php is the integration point. The recommended pattern is:
# Run the cron orchestrator every 5 minutes
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron.php >> /var/log/simplerisk/cron.log 2>&1
The orchestrator's internal scheduling (managed via get_cron_jobs()) handles the per-script cadence; you don't need to schedule each script individually if you're using the orchestrator pattern.
For installations that prefer per-script cron entries (more visibility, more control over individual schedules), schedule each script below directly. Both patterns work.
The recurring scripts
cron_assessments.php
Purpose: Drives the Assessments Extra's scheduled work — sending recurring questionnaires, processing pending risks from completed assessments, dispatching reminder emails to assessment contacts whose responses are overdue.
Extra dependency: Requires the Assessments Extra (assessments_extra()) to be active. If the Extra isn't active, the script no-ops.
Recommended schedule: Every 15 minutes. Frequent enough that scheduled assessments dispatch on time; rare enough that the cron isn't continuously firing during low-volume periods.
Recommended cron entry:
*/15 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_assessments.php >> /var/log/simplerisk/cron.log 2>&1
cron_audit.php
Purpose: Initiates auto-scheduled control test audits. When a control test in the Compliance module has its auto_audit_initiation flag enabled and its scheduled date arrives, this cron creates the audit instance.
Extra dependency: None — uses Core compliance functionality. Runs in any install regardless of which Extras are active.
Recommended schedule: Daily, ideally during off-hours (late evening or early morning) so the auto-initiated audits land before the workday starts.
Recommended cron entry:
0 2 * * * /usr/bin/php /var/www/simplerisk/cron/cron_audit.php >> /var/log/simplerisk/cron.log 2>&1
cron_backup.php
Purpose: Runs the built-in backup mechanism. When backup_auto is set to 'true', invokes do_backup() to produce zip files of the application and database. Records the backup in the backups table. Logs to audit_log with log_type='backup'.
Extra dependency: None — Core feature.
Recommended schedule: Daily, scheduled during off-hours when database activity is low. The backup_schedule setting nominally controls cadence, but the cron job's actual fire time is what determines when backups happen.
Recommended cron entry:
0 3 * * * /usr/bin/php /var/www/simplerisk/cron/cron_backup.php >> /var/log/simplerisk/cron.log 2>&1
For installations using external mysqldump-based backups instead (per Database Backup and Restore), set backup_auto to 'false' and skip this cron entry.
cron_notification.php
Purpose: Drives the Notification Extra's email dispatch. Reads queued notifications from the database and sends them via the configured SMTP server.
Extra dependency: Requires the Notification Extra (notification_extra()) to be active. If the Extra isn't active, the script no-ops and no email notifications fire from SimpleRisk at all.
Recommended schedule: Every 5 to 10 minutes. Frequent enough that notifications arrive promptly; not so frequent that the cron is continuously running.
Recommended cron entry:
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_notification.php >> /var/log/simplerisk/cron.log 2>&1
This is the most commonly-overlooked cron. Without it running, the operational signals SimpleRisk depends on (review reminders, new-risk notifications, audit-initiation alerts) go silent.
cron_vulnmgmt.php
Purpose: Drives the Vulnerability Management Extra's scanner sync. Polls the configured scanner platforms (Qualys, Rapid7 InsightVM Cloud/On-Premise, Nexpose, Tenable.io) for new vulnerability data and writes it to the vulnmgmt_
tables. Optionally auto-triages vulnerabilities to risks per the extra_vulnmgmt_triage_vulnerabilities_by_score configuration.
Extra dependency: Requires the Vulnerability Management Extra (vulnmgmt_extra()) to be active.
Recommended schedule: Per the extra_vulnmgmt_cron_schedule setting, typically hourly for active scanners, daily for less-active ones. The script respects an internal MySQL advisory lock (GET_LOCK('vulnmgmt_update', 0)) to prevent concurrent runs even if the cron fires faster than the previous invocation completed.
Recommended cron entry:
0 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_vulnmgmt.php >> /var/log/simplerisk/cron.log 2>&1
cron_temporary_cleanup.php
Purpose: Deletes rows from the tmp_files table older than 24 hours. The table holds short-lived data (in-progress uploads, intermediate processing artifacts); without periodic cleanup, it accumulates.
Extra dependency: None — Core feature.
Recommended schedule: Daily.
Recommended cron entry:
0 4 * * * /usr/bin/php /var/www/simplerisk/cron/cron_temporary_cleanup.php >> /var/log/simplerisk/cron.log 2>&1
cron_tfidf_recalculation.php
Purpose: Rebuilds TF-IDF (term frequency-inverse document frequency) document scoring via compute_document_control_scores(). Used for full-text search optimization within document content.
Extra dependency: None directly, though benefit depends on having documents in the document library.
Recommended schedule: Weekly. The TF-IDF computation is compute-heavy but the document corpus changes slowly; weekly recomputation is sufficient for most installs.
Recommended cron entry:
0 5 * * 0 /usr/bin/php /var/www/simplerisk/cron/cron_tfidf_recalculation.php >> /var/log/simplerisk/cron.log 2>&1
(Sunday at 5 AM in this example.)
The long-running worker scripts
These three scripts run for up to 60 minutes per invocation, processing async work from queues. They self-terminate after their max runtime; the next cron invocation picks up a fresh process. The pattern is intentional — long-running PHP processes can develop memory issues, so periodic restart keeps them clean.
cron_promise_worker.php
Purpose: Long-running worker (up to 60 minutes per invocation, 512MB memory limit) that processes async promises. Manages zombie workers via lock file detection, acquires single-instance locks, handles signals (SIGTERM for graceful shutdown), and retries failed jobs with exponential backoff.
Extra dependency: None — Core feature used by various subsystems for async work.
Recommended schedule: Every 5 minutes. The worker self-terminates after 60 minutes; if the cron fires while a previous worker is still running, the lock file prevents the duplicate invocation.
Recommended cron entry:
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_promise_worker.php >> /var/log/simplerisk/cron.log 2>&1
cron_queue_loader.php
Purpose: Long-running queue orchestrator (up to 60 minutes per invocation) that loads work items from queues into the promise system and manages worker lifecycle. Implements zombie detection and lock-based single-instance guarantee.
Extra dependency: None — Core feature.
Recommended schedule: Every 5 minutes (same pattern as the promise worker).
Recommended cron entry:
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_queue_loader.php >> /var/log/simplerisk/cron.log 2>&1
cron_queue_worker.php
Purpose: Long-running worker (up to 60 minutes per invocation, 512MB memory limit) that executes queued jobs asynchronously. Handles email delivery, document handling, and other queued background work. Monitors for stuck tasks and zombie workers.
Extra dependency: None — Core feature.
Recommended schedule: Every 5 minutes.
Recommended cron entry:
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_queue_worker.php >> /var/log/simplerisk/cron.log 2>&1
The full recommended crontab
For a typical production install with the standard Extras active, a complete crontab looks roughly like this (run as the web server user, e.g., www-data or apache):
# SimpleRisk cron jobs
# Notifications - every 5 minutes
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_notification.php >> /var/log/simplerisk/cron.log 2>&1
# Async workers - every 5 minutes
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_promise_worker.php >> /var/log/simplerisk/cron.log 2>&1
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_queue_loader.php >> /var/log/simplerisk/cron.log 2>&1
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_queue_worker.php >> /var/log/simplerisk/cron.log 2>&1
# Assessments - every 15 minutes
*/15 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_assessments.php >> /var/log/simplerisk/cron.log 2>&1
# Vulnerability management - hourly
0 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_vulnmgmt.php >> /var/log/simplerisk/cron.log 2>&1
# Daily maintenance
0 2 * * * /usr/bin/php /var/www/simplerisk/cron/cron_audit.php >> /var/log/simplerisk/cron.log 2>&1
0 3 * * * /usr/bin/php /var/www/simplerisk/cron/cron_backup.php >> /var/log/simplerisk/cron.log 2>&1
0 4 * * * /usr/bin/php /var/www/simplerisk/cron/cron_temporary_cleanup.php >> /var/log/simplerisk/cron.log 2>&1
# Weekly TF-IDF recalculation
0 5 * * 0 /usr/bin/php /var/www/simplerisk/cron/cron_tfidf_recalculation.php >> /var/log/simplerisk/cron.log 2>&1
(Adjust the PHP binary path, the SimpleRisk install path, and the log path for your environment.)
For containerized deployments where the Docker image runs cron internally, the operator-side cron is replaced by the image's own scheduling. Verify which pattern your image uses; see Installing via Docker.
For Kubernetes deployments, each cron script becomes a CronJob resource; the schedule maps directly to the spec.schedule field. The long-running workers can also be modeled as Deployment resources rather than CronJob for continuous operation.
Verifying cron is running
After configuring the crontab, verify the cron jobs actually run:
# Check the cron daemon is active
sudo systemctl status cron # Debian/Ubuntu
sudo systemctl status crond # RHEL/Rocky/Alma
# Tail the cron output log
sudo tail -f /var/log/simplerisk/cron.log
# Check the cron_last_run setting
mysql -u root -p simplerisk -e "SELECT value FROM settings WHERE name='cron_last_run';"
The cron_last_run setting updates on each invocation of cron.php; a recent value confirms the orchestrator is firing. Per-script verification can be done by checking each script's specific behavior (the notification cron updates a queue counter; the backup cron creates a row in the backups table; etc.).
Common pitfalls
A handful of patterns recur with cron management.
-
Not configuring cron at all. The single most common operational failure. SimpleRisk gets installed, the application works, the operator moves on, and weeks later wonders why notifications aren't firing. Always configure cron as part of the install procedure, not as an afterthought.
-
Running cron as the wrong user. SimpleRisk's cron scripts need filesystem access to the SimpleRisk install (to read source, write logs) and database access (via the SimpleRisk MySQL user). Running as the web server user (
www-data/apache) is the right pattern; running asrootworks but is unnecessary privilege escalation. -
Cron silently failing without surfacing the error. A cron script that errors writes to its stderr; if the cron entry redirects stderr to
/dev/null(or omits redirection entirely), the error is lost. Use>> /var/log/simplerisk/cron.log 2>&1to capture both stdout and stderr to a file you can review. -
Long-running worker scripts being run as one-off cron entries that don't account for their lifetime. The promise worker runs for up to 60 minutes; if you schedule it every minute, you accumulate 60 concurrent worker processes. The lock-file mechanism prevents most damage, but the cleaner pattern is "schedule every 5 minutes; the lock prevents overlap." Don't schedule too aggressively.
-
Missing PHP binary path on cron's $PATH. Cron's environment is much more minimal than an interactive shell's. Without the full path to
php(or appropriatePATH=variable in the crontab), the script invocation fails with "command not found." Always use the full path to the PHP binary. -
Cron running but cron_last_run not updating. This signals that
cron.phpisn't being invoked (or is erroring before it can write the setting). Investigate by running the script manually and observing the output. -
Over-scheduling vulnerability syncs hitting scanner API rate limits. Some scanner APIs rate-limit aggressively. Hourly polling is generally safe; finer cadences may produce 429 (Too Many Requests) responses. Check your scanner's rate limits and adjust accordingly.
-
Backup cron running during heavy database load. A
mysqldump(whichcron_backup.phpinvokes internally) during peak load can degrade application performance. Schedule backups during off-hours. -
Forgetting to update cron after upgrading SimpleRisk to a release that adds new cron scripts. New SimpleRisk releases sometimes introduce new cron scripts. Operators relying on the orchestrator pattern (
cron.php) get the new scripts automatically; operators with per-script cron entries need to add the new ones manually after each upgrade. Review release notes for new cron scripts. -
Running cron on multiple SimpleRisk hosts simultaneously without coordination. A scaled-out deployment with multiple SimpleRisk hosts behind a load balancer should run cron on one host (or one dedicated cron-runner host), not on all of them. Multiple concurrent cron invocations produce duplicate notifications and racing on shared resources. Designate one host (or a separate cron-only host) for cron.
Related
- The Upgrade Process
- Database Backup and Restore
- Log Rotation and Disk Management
- Installing on Linux
- Installing via Docker
- Notifications and Email Preferences
- The Vulnerability Management Extra
- Monitoring SimpleRisk
Reference
- Permission required: Server-side: cron-management privileges; web server user filesystem access; SimpleRisk MySQL user database access.
- API endpoint(s): None for cron management directly. Some Extras have API endpoints to trigger work that cron also fires (e.g.,
GET /api/v2/vulnmgmt/update/allfor an on-demand sync). - Implementing files:
simplerisk/cron/cron.php(orchestrator);simplerisk/cron/cron_assessments.php,cron_audit.php,cron_backup.php,cron_notification.php,cron_vulnmgmt.php,cron_temporary_cleanup.php,cron_tfidf_recalculation.php(recurring scripts);simplerisk/cron/cron_promise_worker.php,cron_queue_loader.php,cron_queue_worker.php(long-running workers). - Database tables:
settings(thecron_last_runtimestamp; per-Extra*_extra_cron_*schedule keys); plus the tables each script reads/writes. config_settingskeys:cron_last_run(Unix timestamp of lastcron.phpinvocation);backup_auto,backup_schedule,backup_path,backup_remove(built-in backup);extra_vulnmgmt_cron_auto,extra_vulnmgmt_cron_schedule(vulnmgmt sync cadence).- External dependencies: OS-level scheduler on the supported Linux host (Linux cron, systemd timers, Kubernetes CronJob); per-Extra dependencies (SMTP for notification, scanner APIs for vulnmgmt, etc.).