---
title: 02.07 The Cron Jobs
description: Reference catalog of the 10 cron scripts under simplerisk/cron/ — what each does, when to schedule it, which Extras it depends on, and the long-running…
---

[Skip to content](https://support.simplerisk.com/kb/02-07-the-cron-jobs#main-content)

English

Show submenu for translations

[Customer portal](https://support.simplerisk.com/tickets?hsLang=en)

[![SimpleRisk logo of a man walking a tight rope](https://support.simplerisk.com/hs-fs/hubfs/simplerisk_logo_long_small-4.png?width=377&height=72&name=simplerisk_logo_long_small-4.png)](https://www.simplerisk.com/)

Open main navigation

Close main navigation

- English
  
  Show submenu for translations
- [Customer portal](https://support.simplerisk.com/tickets)
- [Contact us](https://www.simplerisk.com/about-us/contact-us)

[Contact us](https://www.simplerisk.com/about-us/contact-us)

 How can we help you?

- There are no suggestions because the search field is empty.

1. [SimpleRisk Knowledge Base](https://support.simplerisk.com/kb?hsLang=en)
2. [Administrator Guide](https://support.simplerisk.com/kb/administrator-guide?hsLang=en)
3. [02 Upgrades and Maintenance](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#02-upgrades-and-maintenance)

# 02.07 The Cron Jobs

## Reference catalog of the 10 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 by default (the `QUEUE_WORKER_MAX_RUNTIME_MINUTES` setting; see [Tuning the workers](https://support.simplerisk.com/kb/02-07-the-cron-jobs#tuning-the-workers)), 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 runs every scheduled job that's due. On each run, it:

- Writes a start entry to the debug log.
- Updates the `cron_last_run` setting 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 minute
* * * * * /usr/bin/php /var/www/simplerisk/cron/cron.php >> /var/log/simplerisk/cron.log 2>&1
```

The orchestrator handles each job's own cadence internally, so you don't need to schedule the individual scripts yourself if you're using it. Run it every minute, which is the crontab line SimpleRisk itself suggests on the backup settings page: it starts a background worker whenever one is missing, runs the queue loader, and only runs the hourly, daily and weekly jobs when they're due. A run that finds every worker already in place starts no new worker.

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** to be active. If it isn't, the script does nothing.

**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
```

> **Retired**: `cron_audit.php` no longer exists. Compliance audit auto-initiation moved to the queue job system — the `core_audit_initiate` job, driven by the long-running worker scripts described below (`cron_queue_loader.php` / `cron_queue_worker.php`). If you have an existing crontab entry for `cron_audit.php`, remove it; the script isn't in `simplerisk/cron/` anymore and the entry will just fail silently every time it fires.

#### cron\_backup.php

**Purpose**: Runs the built-in backup. When automatic backups are switched on, it produces a zip of the application and a zip of the database, records the backup, and writes a backup entry to the audit trail.

**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](https://support.simplerisk.com/kb/02-05-database-backup-and-restore?hsLang=en)), 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** to be active. If it isn't, the script does nothing 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_{platform}_*` tables. Optionally auto-triages vulnerabilities to risks per the `extra_vulnmgmt_triage_vulnerabilities_by_score` configuration.

**Extra dependency**: Requires the **Vulnerability Management 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 takes an internal lock so two runs can't overlap, even if cron fires again before the previous run has finished.

**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 the relevance scoring behind document search, so full-text search across document content stays fast and accurate.

**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 by default, 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.

Upgrades recycle the workers automatically. When an upgrade completes (a database migration or an application-file update), SimpleRisk records a restart request in the `settings` table as `worker_restart_requested_at`. Every worker that started before the request finishes its current task, exits cleanly, and comes back on the next cron tick running the new code. Without this, a worker started before the upgrade would keep the old code in memory for up to an hour and could fail on functions the new release renamed. Sending SIGHUP to a worker process triggers the same graceful recycle by hand. Editing `config.php` does too: each worker notices the change, finishes its current task and exits, so new settings take effect without a manual restart (see [Tuning the workers](https://support.simplerisk.com/kb/02-07-the-cron-jobs#tuning-the-workers)).

#### cron\_promise\_worker.php

**Purpose**: Long-running worker (by default 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, SIGHUP for a graceful recycle), and retries failed jobs with exponential backoff.

**Extra dependency**: None — Core feature used by various subsystems for async work.

**Recommended schedule**: Every 5 minutes, or every minute so a worker that exits is replaced sooner. The worker self-terminates after 60 minutes by default; if the cron fires while the configured number of step workers is already running, the new run exits at once.

**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 (by default 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 (by default up to 60 minutes per invocation, 512MB memory limit) that executes queued jobs asynchronously. Handles email delivery, document handling, compliance audit auto-initiation (the `core_audit_initiate` job, which replaced the old `cron_audit.php` script), network asset discovery runs started from the Manage Assets page, and other queued background work. Monitors for stuck tasks and zombie workers. If discovery runs sit at queued and never start, this worker isn't running. After a deploy that adds a new kind of queued job, restart long-running workers so they pick up the new code; until they recycle, tasks for the new job fail with a "no job definition" error.

**Extra dependency**: None — Core feature.

**Recommended schedule**: Every 5 minutes, or every minute (same pattern as the promise worker).

**Recommended cron entry**:

```
*/5 * * * * /usr/bin/php /var/www/simplerisk/cron/cron_queue_worker.php >> /var/log/simplerisk/cron.log 2>&1
```

### Tuning the workers

The 60-minute lifetime, the 512MB memory limit and the retry timing quoted above are defaults, not fixed values. Each one can be changed with a `define()` line in `includes/config.php`, the same file that holds the database connection details. A fresh `config.sample.php` lists every one of them, commented out, in a section headed "Background task / queue worker tuning (optional)". Copy the line you want into `config.php`, remove the leading `//`, and change the number. Leave everything else alone. Adding none of these lines is safe; the defaults suit most installs.

A few things changed for every install, whether or not you add any lines:

- The workers coordinate through MySQL named locks, which needs no extra database permission (see [Running more than one worker](https://support.simplerisk.com/kb/02-07-the-cron-jobs#running-more-than-one-worker)).
- A worker's database connection is closed by the database once it has been idle for the stuck-task window, half an hour by default.
- A task or step that stops part-way, because its worker crashed, ran out of memory, was killed or lost its database connection, is run again only a limited number of times and then marked failed, and the admins are notified.
- Workflow tasks are never retried automatically.
- When the cron jobs run on more than one server, a worker on another server that hasn't checked in for five minutes is treated as gone.
- Calls to an AI provider give up after 10 minutes in total, retries and waits included, or after 30 seconds if the provider can't be reached at all.

```
// Give the workers more memory headroom for large document imports
define('QUEUE_WORKER_MEMORY_SOFT_LIMIT_MB', 900);
define('QUEUE_WORKER_PHP_MEMORY_LIMIT_MB', 1024);
```

Values are whole numbers. A value outside the range in the table is pulled back to the nearest end of the range, and a value that isn't a whole number (`'1G'`, `'512M'`, `2.5`) is ignored in favor of the default. Neither mistake stops the workers, so check the number you typed rather than waiting for an error.

#### `QUEUE_WORKER_MEMORY_SOFT_LIMIT_MB`

- **Default:** 400
- **Range:** 64–8192
- **What it controls:** Memory, as PHP counts it, above which a worker exits cleanly between tasks and is restarted by cron
- **When to change it:** Workers recycle constantly on a busy install, or document text extraction keeps running out of room

#### `QUEUE_WORKER_PHP_MEMORY_LIMIT_MB`

- **Default:** 512
- **Range:** 128–8192
- **What it controls:** The hard PHP memory limit for the workers; a single task that goes past it fails
- **When to change it:** Raise it together with the soft limit. It's always kept at least 64MB above the soft limit, so a soft limit of 8192 lifts it to 8256

#### `QUEUE_WORKER_MAX_RUNTIME_MINUTES`

- **Default:** 60
- **Range:** 5–1440
- **What it controls:** How long a worker runs before it exits and the next cron run starts a fresh one
- **When to change it:** Rarely; a shorter lifetime limits how long a slow memory leak can grow

#### `QUEUE_WORKER_MAX_IDLE_MINUTES`

- **Default:** 60
- **Range:** 5–1440
- **What it controls:** How long a worker may sit with nothing to do before it exits
- **When to change it:** Rarely

#### `QUEUE_WORKER_LOOP_DELAY_SECONDS`

- **Default:** 3
- **Range:** 1–60
- **What it controls:** The queue worker's pause between tasks and between checks of an empty queue
- **When to change it:** Raise it to lower database polling on a quiet install

#### `PROMISE_WORKER_LOOP_DELAY_SECONDS`

- **Default:** 5
- **Range:** 1–60
- **What it controls:** The step worker's pause between batches of steps
- **When to change it:** Same as above, for multi-step work such as AI document processing

#### `QUEUE_STUCK_TASK_MINUTES`

- **Default:** 30
- **Range:** 5–1440
- **What it controls:** The stuck-task window. A task or step that a running worker is still working on is never put back in the queue, however long it takes; this window only applies to work whose worker is gone, which goes back in the queue once it has shown as running this long. It's also how long a worker's database connection may sit idle before the database closes it (never less than 15 minutes): a task or step that makes no database request for longer than this loses its place and may run again. And it's the shortest time after a cancel that the Queue Monitor's bulk delete waits before treating the task as settled, never less than 30 minutes, however low this is set
- **When to change it:** Raise it when a single task or step legitimately goes longer than 30 minutes without touching the database

#### `QUEUE_RECOVERY_MAX_ATTEMPTS`

- **Default:** 5
- **Range:** 1–20
- **What it controls:** How many times a task or step that stopped part-way, because its worker crashed, ran out of memory, was killed or lost its database connection, is put back in the queue. The next time it's found that way it's marked failed instead, and the admins get the failed-task notification
- **When to change it:** Rarely. Lower it if a task that keeps dying is costing you something each time it runs again, such as AI calls; raise it if a flaky host kills workers often and the tasks do finish on a later try

#### `QUEUE_RETRY_MAX_ATTEMPTS`

- **Default:** 5
- **Range:** 0–20
- **What it controls:** How many times a failed task is retried before it's marked failed. A step inside a multi-step task gets this many attempts in total, so the same value gives a task one more try than a step
- **When to change it:** Raise it on an install whose AI provider or other outside service has frequent short outages; `0` fails a task on its first error

#### `QUEUE_RETRY_BASE_DELAY_SECONDS`

- **Default:** 5
- **Range:** 1–3600
- **What it controls:** The wait before the first retry; each further retry waits twice as long as the one before
- **When to change it:** Raise it so retries spread over a longer outage. With the defaults a task's five retries are spent within about two and a half minutes

#### `QUEUE_RETRY_MAX_DELAY_SECONDS`

- **Default:** 3600
- **Range:** 1–86400
- **What it controls:** The longest wait between two retries. It's never allowed below the base delay
- **When to change it:** Lower it to cap the gap between retries once the base delay is raised

#### `PROMISE_WORKER_BATCH_SIZE`

- **Default:** 20
- **Range:** 1–200
- **What it controls:** How many ready steps the step worker picks up in one batch
- **When to change it:** Lower it if one batch of heavy steps pushes the worker past its memory limit

#### `WORKER_STALE_LOCK_SECONDS`

- **Default:** 86400
- **Range:** 300–604800
- **What it controls:** How long a running worker may go without checking in before the next worker started on the same server treats it as hung, stops it and takes its place. A worker whose process has already gone is replaced straight away, whatever this is set to
- **When to change it:** Rarely. Keep it well above the longest time any single task can take: a worker busy with one long task doesn't check in, and a value below that task's run time gets a healthy worker stopped part-way

#### `QUEUE_WORKER_COUNT`

- **Default:** 1
- **Range:** 1–10
- **What it controls:** How many queue workers may run at the same time across the whole installation
- **When to change it:** Queued email or other single-step tasks pile up behind each other, or one long task holds up everything else. See [Running more than one worker](https://support.simplerisk.com/kb/02-07-the-cron-jobs#running-more-than-one-worker) first

#### `PROMISE_WORKER_COUNT`

- **Default:** 1
- **Range:** 1–10
- **What it controls:** How many step workers may run at the same time across the whole installation
- **When to change it:** Multi-step work falls behind: document and control processing, and AI analysis of documents, controls or risks. Same cautions as above

Some tasks ask for their own retry timing when they're queued, and for those the task's own values win over the retry settings. User imports do, and so does queued email, which asks for a five-minute first wait. Each retry after that waits twice as long, up to the longest retry wait (an hour by default), and the number of retries follows the retry setting. At the defaults that rides out a mail outage of about two and a quarter hours before the send is reported as failed. Workflow tasks are the opposite case. They're never retried, because some of a workflow's actions may already have fired, so a workflow task's first error fails it and the admins are notified. Everything else follows the table.

You don't need to restart anything after an edit. The three worker scripts check `config.php` as they work. When the file has changed since a worker started, the worker finishes its current task, exits, and the next cron run starts it again with the new values. On the recommended five-minute schedule that's a few minutes after the save, plus however long the task in hand takes to finish.

Two cautions on memory. Each worker is its own PHP process, so the hard limit applies once per running worker (three times over with the default single queue worker, step worker and loader), and the web server's PHP processes still need their own share of the host's memory. Size the limits against what the host can actually spare. The second caution is that some document formats, spreadsheets in particular, are unpacked by libraries that allocate memory PHP doesn't count. A very large file can push the process well past either limit before PHP notices, so a higher limit isn't a cure for a single oversized upload.

#### Running more than one worker

By default one queue worker and one step worker run, and that's always a safe setting. When background work piles up you can let several run side by side:

```
// Up to three queue workers and two step workers at the same time
define('QUEUE_WORKER_COUNT', 3);
define('PROMISE_WORKER_COUNT', 2);
```

Pick the kind of worker that matches the backlog. Most heavy work, such as processing documents and controls or running AI analysis, happens in steps, so more step workers is what speeds it up. Queue workers run each task's first part and the single-step tasks, such as sending queued email, so extra queue workers help when email or similar tasks pile up, or when one long task would otherwise hold up everything behind it.

The numbers are for the whole installation, not per server. When several web servers run the cron jobs against one database, they share the same workers between them. Keep `config.php` the same on every server, because the Queue Monitor compares the running workers against the number in the `config.php` of the server that shows the page.

Workers don't all start at once. Each run of a worker's cron entry starts at most one more, until the configured number is running. The `cron.php` orchestrator gives each configured worker its own entry, so with `cron.php` run every minute they're all running within a minute or two. With a separate cron line per worker script, each run of that line adds one worker: on a five-minute schedule, three queue workers take up to fifteen minutes to reach full strength. Running the worker lines every minute is fine, because a run that finds every worker already in place exits straight away. Lowering the number works the other way round: the edit restarts every worker, and only the new number of them start again.

Every task and every step still runs once, however many workers there are, with one exception: a worker that loses its database connection in the middle of a task. That includes a task or step that makes no database request for longer than the stuck-task window (half an hour by default), because the database then closes the idle connection. Another worker, or the same one after it reconnects, can then run that work again, possibly while the first run is still finishing. Each such re-run counts toward `QUEUE_RECOVERY_MAX_ATTEMPTS`, so it can't repeat forever. Calls to an AI provider give up after 10 minutes in total, inside that window even at its lowest setting, so a stalled provider on its own doesn't trigger this; a task that also does other slow work without touching the database still can. If you see repeated re-runs, raise `QUEUE_STUCK_TASK_MINUTES` or fix whatever drops the connections.

Most kinds of task run one at a time whatever the count: a task of one of these kinds never starts while another task of the same kind is starting or running. That covers everything except the kinds known to be safe side by side, which are queued email, document and control processing, and the AI tasks that work on one document, control or risk at a time. Two different kinds can still run at the same time. For multi-step work this only applies to starting the task. The steps of the Encrypted Database tasks, the ComplianceForge SCF install and the AI context refresh are kept to one run at a time because SimpleRisk never starts a second one while one is in progress, not by this rule.

Each extra worker costs what the first one does. It's another PHP process that may use up to the memory limit above, and another database connection held open for as long as it runs. Check the host's memory and the database's connection limit before raising either number.

The workers coordinate through MySQL's named locks, at every worker count including the default of one. That needs no extra database permission, but it does bring two requirements:

- **A single MySQL 8 server, or a primary with read replicas.** A multi-writer cluster such as Galera, where several nodes accept writes, doesn't share these locks between nodes. Point every server that runs the worker scripts at the same node, or run the worker scripts on only one server.
- **No connection pooling that swaps connections mid-session.** A proxy or pooler between SimpleRisk and MySQL must keep each worker on one backend connection for as long as it's connected. Transaction-level pooling hands a connection to someone else between statements and breaks the locks. Session-level pooling, or a direct connection, is fine.

If the database refuses the locks altogether, the workers don't start, and the debug log says why. Nothing runs twice; nothing runs at all until the locks work.

When the cron jobs run on more than one server, a worker on another server counts as running for five minutes after it last checked in. A server that was replaced, such as a redeployed container, gives up its workers' places within those five minutes, so a new server isn't kept waiting. Taking a place over never touches the old worker: if it was only busy, it notices and stops after its current task. A server that disappeared without closing its database connections can still hold on to the task it was running. The workers ask MySQL to close a connection that has been idle for the stuck-task window (half an hour by default, never less than 15 minutes, and never longer than the database's own limit), so such a task is free again within that time.

The [Queue Monitor](https://support.simplerisk.com/kb/12-08-monitoring-background-tasks?hsLang=en) shows how many workers are running against how many are configured, for example "Running · 2 of 3", once a number is above 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 (also drives compliance audit auto-initiation)
*/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 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](https://support.simplerisk.com/kb/01-03-installing-via-docker?hsLang=en).

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 as `root` works 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>&1` to capture both stdout and stderr to a file you can review.
- **Scheduling the worker scripts too rarely.** A worker runs for up to 60 minutes by default and then exits; until the next cron run starts it again, nothing is processed. Scheduling the worker scripts every minute (or running `cron.php` every minute) is safe: a run that finds the configured number of workers already running exits at once, so processes don't pile up. Hourly or rarer schedules leave long gaps.
- **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 appropriate `PATH=` 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.php` isn'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` (which `cron_backup.php` invokes 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 every cron script on multiple SimpleRisk hosts.** The three worker scripts coordinate through the database, so they can run on several hosts at once: they share the configured number of workers and each task runs once (see [Running more than one worker](https://support.simplerisk.com/kb/02-07-the-cron-jobs#running-more-than-one-worker)). The other scripts (notifications, backups, assessments, vulnerability syncs, cleanup) don't coordinate, and running them on several hosts produces duplicate notifications and races on shared resources. On a scaled-out deployment, run those on *one* host (or a dedicated cron-runner host). The simplest setup runs `cron.php` on that one host only.

## Related

- [The Upgrade Process](https://support.simplerisk.com/kb/02-01-the-upgrade-process?hsLang=en)
- [Database Backup and Restore](https://support.simplerisk.com/kb/02-05-database-backup-and-restore?hsLang=en)
- [Log Rotation and Disk Management](https://support.simplerisk.com/kb/02-06-log-rotation-and-disk-management?hsLang=en)
- [Installing on Linux](https://support.simplerisk.com/kb/01-02-installing-on-linux?hsLang=en)
- [Installing via Docker](https://support.simplerisk.com/kb/01-03-installing-via-docker?hsLang=en)
- [Notifications and Email Preferences](https://support.simplerisk.com/kb/09-05-notifications-and-email-preferences?hsLang=en)
- [The Vulnerability Management Extra](https://support.simplerisk.com/kb/05-03-the-vulnmgmt-extra?hsLang=en)
- [Monitoring SimpleRisk](https://support.simplerisk.com/kb/12-01-monitoring-simplerisk?hsLang=en)

- [FAQs](https://support.simplerisk.com/kb/faqs?hsLang=en)
- [SimpleRisk Extras](https://support.simplerisk.com/kb/simplerisk-extras?hsLang=en#main-content)

    - [Vulnerability Management Extra](https://support.simplerisk.com/kb/simplerisk-extras?hsLang=en#vulnerability-management-extra)
    - [Team Separation Extra](https://support.simplerisk.com/kb/simplerisk-extras?hsLang=en#team-separation-extra)
    - [Import-Export Extra](https://support.simplerisk.com/kb/simplerisk-extras?hsLang=en#import-export-extra)
- [Administrator Guide](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#main-content)

    - [00 About This Guide](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#00-about-this-guide)
    - [01 Installation and Deployment](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#01-installation-and-deployment)
    - [02 Upgrades and Maintenance](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#02-upgrades-and-maintenance)
    - [03 Users and Permissions](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#03-users-and-permissions)
    - [04 Authentication](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#04-authentication)
    - [05 Customization](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#05-customization)
    - [06 Configuring Risk and Compliance](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#06-configuring-risk-and-compliance)
    - [07 Integrations](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#07-integrations)
    - [08 The API](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#08-the-api)
    - [09 Encryption and Data Security](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#09-encryption-and-data-security)
    - [10 Workflows and Automation](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#10-workflows-and-automation)
    - [11 Reporting and Auditing](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#11-reporting-and-auditing)
    - [12 Operations](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#12-operations)
    - [13 Reference](https://support.simplerisk.com/kb/administrator-guide?hsLang=en#13-reference)
- [User Guide](https://support.simplerisk.com/kb/user-guide?hsLang=en#main-content)

    - [00 Foundations of GRC](https://support.simplerisk.com/kb/user-guide?hsLang=en#00-foundations-of-grc)
    - [01 Risk Management](https://support.simplerisk.com/kb/user-guide?hsLang=en#01-risk-management)
    - [02 Compliance Management](https://support.simplerisk.com/kb/user-guide?hsLang=en#02-compliance-management)
    - [03 Governance](https://support.simplerisk.com/kb/user-guide?hsLang=en#03-governance)
    - [04 Asset and Data Inventory](https://support.simplerisk.com/kb/user-guide?hsLang=en#04-asset-and-data-inventory)
    - [05 Threat and Vulnerability Management](https://support.simplerisk.com/kb/user-guide?hsLang=en#05-threat-and-vulnerability-management)
    - [06 Assessments](https://support.simplerisk.com/kb/user-guide?hsLang=en#06-assessments)
    - [07 Incident Management](https://support.simplerisk.com/kb/user-guide?hsLang=en#07-incident-management)
    - [08 Audit and Reporting](https://support.simplerisk.com/kb/user-guide?hsLang=en#08-audit-and-reporting)
    - [09 Day-to-Day SimpleRisk](https://support.simplerisk.com/kb/user-guide?hsLang=en#09-day-to-day-simplerisk)
    - [10 Continuous Improvement](https://support.simplerisk.com/kb/user-guide?hsLang=en#10-continuous-improvement)
- [SimpleRisk User Guides](https://support.simplerisk.com/kb/simplerisk-user-guides?hsLang=en)
- [Troubleshooting](https://support.simplerisk.com/kb/troubleshooting?hsLang=en)
- [SimpleRisk Hosted](https://support.simplerisk.com/kb/simplerisk-hosted?hsLang=en)
- [How To videos](https://support.simplerisk.com/kb/how-to-videos?hsLang=en)

[![favicon-1](https://support.simplerisk.com/hs-fs/hubfs/favicon-1.png?width=35&height=35&name=favicon-1.png "favicon-1")](https://www.simplerisk.com)

<https://www.facebook.com/simplerisk/> <https://www.twitter.com/simpleriskfree/> <https://www.linkedin.com/company/simplerisk/>

Copyright © 2026, SimpleRisk, Inc.