Job engine troubleshooting
When jobs stop moving, check the job’s status first
4 minute read
Each unit of that work is a job, with its own status, progress messages, and log. The job engine retrieves pending jobs from the database, runs each in its own thread, and writes progress back as each job runs.
run() method finishes and returns a result. The job then ends as SUCCESS, WARNING, or FAILURE.Potential interruptions:
Check a job’s status first when work looks stuck.
| Status | Shown as | Meaning |
|---|---|---|
INIT |
Initializing | Created, but held back on purpose. Workers ignore the job until something sets it to PENDING. |
PENDING |
Pending | Waiting to be claimed. A job scheduled for a future time stays here until that time arrives. |
QUEUED |
Queued | Claimed by a worker and waiting for a free thread. |
RUNNING |
Running | Executing in a worker thread. |
PAUSED |
Paused | Stopped inside plugin code that is running in debug mode. Only an administrator can resume it. |
STEP |
Step | Resumed from a pause to run one line, stepping into any call it makes. |
NEXT |
Next | Resumed from a pause to run one line, stepping over any call it makes. |
RETURN |
Run until return | Resumed from a pause to run until the current function returns. |
TO_CANCEL |
In cancellation process | Cancellation has been requested. A job that is already running may sit here briefly before it reaches CANCELED. |
CANCELED |
Canceled by user | Stopped before it finished. The global job timeout and the cleanup of jobs whose workers died also end in this status. |
SUCCESS |
Completed successfully | Finished with no errors reported. |
WARNING |
Completed with warnings | Finished, but something in the job reported a warning. Read the job’s log before treating the work as done. |
FAILURE |
Completed with errors | Finished with an error. The job engine itself is working; troubleshoot the job. |
You can use shell_plus to list jobs by state:
Job.objects.filter(status__in=Job.ACTIVE_STATUSES)
Job.objects.filter(status__in=Job.RUNNING_STATUSES)
Job.objects.filter(status__in=Job.COMPLETED_STATUSES)
The job engine runs under Supervisor on the appliance, configured by /etc/supervisord.d/jobengine.conf.
| Setting | Default | Description |
|---|---|---|
numprocs |
1 |
How many worker processes the job engine runs. Each worker runs individual jobs in threads, and each process can use a separate CPU core. Raising this can improve throughput on a busy appliance. |
stopwaitsecs |
600 |
How long Supervisor waits for a worker to exit after telling it to stop, before forcing it with a kill signal. |
autostart |
true |
Whether the workers start when Supervisor starts. Set it to false on a node that should not process jobs, such as a standby node in a high availability deployment. |
The file also carries other Supervisor settings, including how often a stopped worker is retried; see the Supervisor documentation. Upgrading CMP writes an example file, jobengine.conf.template. That file holds the built-in settings for the upgraded release. Use this as a reference when comparing any customized settings on your appliance.
numprocs sets how many workers exist. A separate Django setting, MAX_JOB_CONCURRENCY, sets how many jobs each worker runs at a time, and it defaults to 200. Override it in customer_settings.py.
Each running job holds a database connection, so a worker will stop claiming jobs when PostgreSQL runs short of connections. When a worker cannot start any jobs, it logs that it has no free threads.
/etc/supervisord.d/jobengine.conf and set numprocs to the desired number of workers.supervisorctl reload.Reloading Supervisor restarts every service it manages, not only the job engine. Jobs running at the time are killed and left in RUNNING until the engine cleans them up.
When jobs stop moving, check the job’s status first
The job engine recycles its own workers as it runs
A job engine can be limited to certain kinds of jobs