Background tasks
5 min read
Anything that can take longer than a few seconds does not run while you wait for a page: it runs in the background, in small batches, so a big job never times out and never blocks the site. The engine is Action Scheduler, which ships with the plugin and is also used by WooCommerce and many other plugins. All of this plugin's jobs use the Action Scheduler group wpmcf.
There are two kinds of background work:
Kind | Examples | Where you see it |
|---|---|---|
Tasks (a row in the plugin's task table, with a run log) | Programmatic SEO generation, AI enrichment, page conversion, data table imports and syncs (Pro features) | In the screen of the feature that created the task |
Single jobs | The ACF migration value copy, large field group table changes, syncing field groups registered in PHP | In the screen that started it (for example the progress bar of the migration) |
The free plugin has no separate Tasks screen: a task is always shown by the feature that owns it, and you can list tasks from the command line (wp wpmcf tasks list).
How a run works
- You start the job (or its schedule fires). The plugin queues an Action Scheduler action.
- WordPress runs the action. Each batch works until its budget is spent: about 20 seconds or 80 % of the PHP memory limit, whichever comes first.
- If work remains, the next batch is queued at once. The batches continue until the run finishes.
- When the run finishes the task becomes Completed, or, for a recurring task, waits for its next run (never sooner than one minute).
Each batch continues exactly where the last stopped, so a crash or restart never repeats finished work.
What starts the queue. When you press a button in the admin, the plugin asks Action Scheduler to start right after the request. Otherwise batches are picked up by WP-Cron, roughly every minute while the site gets visits. On sites with little traffic or with WP-Cron disabled, run the queue from a system cron job (see WP-CLI):
wp action-scheduler run --group=wpmcfTask statuses
Status | Meaning |
|---|---|
Active | Runs now, or at its next scheduled time. |
Paused | Never runs until it is activated again. |
Completed | A one-time task finished. |
Failed | The task stopped after too many failed attempts in a row. Activating it again resets the counter. |
Each run also leaves a log entry with the status Processing, Completed or Failed, a message, and the finish time. The last 20 logs of a task are kept.
Failures and retries
A batch that throws an error is not lost:
Attempt | What happens |
|---|---|
1st failure | The task stays Active and retries after 1 minute. |
2nd failure | Retry after 2 minutes. |
3rd failure (the default maximum) | The task becomes Failed, with the error message kept in its state. |
The delay doubles with each attempt up to one hour. A successful batch resets the counter to zero.
To fix a failed task, remove the cause (the message says what failed), then activate the task again from the feature screen or run it with wp wpmcf tasks run <id>.
Locks and the watchdog
- Only one batch of a task runs at a time. A running batch holds a lock for up to 10 minutes.
- If a batch is cut off (a PHP fatal error, a timeout or running out of memory), no follow-up is queued. A watchdog that runs every 15 minutes finds active tasks with no queued action whose last batch is older than 15 minutes, and queues them again.
- When the plugin is deactivated and activated again, active tasks are queued again automatically.
Pause, reset and delete
Action | Result |
|---|---|
Pause | The queued action is removed and the status becomes Paused. A batch that is running finishes and keeps the paused state. |
Reset | Progress and attempts are cleared. An active task starts over immediately. The feature removes its own output. |
Delete | The task, its logs and its queued action are removed. The feature cleans up what the run left behind. |
If the module that owns a task is gone (for example the Pro code was removed), the task is kept but paused, so nothing fails at random. It starts again when the code is back and you activate it.
The ACF migration
The ACF migration does not use the task table. It is one job with its own status:
Status | Meaning |
|---|---|
idle | Nothing has been run. |
running | Batches are queued or running. |
done | Finished. |
cancelled | Stopped with Cancel migration. |
It handles 50 objects per batch inside the same time and memory budget. A batch holds a 10-minute lock. If nothing is queued and nothing moved for five minutes, Resume appears. Details are in Migrating from ACF.
Where to look when something is stuck
- The feature screen (Programmatic SEO, Data tables or Tools › Migrate from ACF): status, last run message and the last error.
- Tools › Scheduled Actions in WordPress (Action Scheduler's own list). Filter by the group
wpmcfand the status Pending, In-progress, Failed. Pending actions with a past date mean the queue is not running: see What starts the queue. - WPM Fields › Settings › Health: errors caught while a job ran. See Health and troubleshooting.
wp wpmcf tasks listshowsstatus,next_runandattemptsfor every task.
Symptom | Likely cause | What to do |
|---|---|---|
Progress does not move | WP-Cron is disabled or the site has no visitors | Run |
Status Failed | Three batches in a row failed | Read the message, fix the cause, activate the task again |
Status Paused and you did not pause it | The owning feature was unavailable (for example Pro removed or the license expired) | Restore it, then activate the task |
A run seems to restart from zero | The task was reset or its data source was replaced | Check the feature's log |
Batches are slow | Shared hosting with a short execution limit | Lower the batch time with the filter below |
For developers
Hook | Kind | Purpose |
|---|---|---|
| Action Scheduler hook | Runs one batch of a task (argument: task id). |
| Action Scheduler hook | The recurring watchdog. |
| action | A run finished (task id, type, state). |
| action | A task failed for good (task id, type, message, task). |
| action | A task was deleted (task id, type, task). |
| filter | Time budget of one batch in seconds (default 20). |
// Shorter batches on a host with a 30 second execution limit.
add_filter( 'wpmcf/jobs/batch_seconds', fn () => 10 );A module registers a handler for its task type in its boot code; a handler must be idempotent, because a batch can be retried after a crash.
Still stuck? Contact support