Jobs/Automated tasks¶
Introduced in v13
A job is a wrapper around a Celery task that can be scheduled, run on demand, and managed via the administration interface. You can also monitor the execution status of each job, run history, and logs.
Scheduler¶
The Invenio job system uses a custom Celery task scheduler which requires a separate Celery beat. You can run the custom beat in a separate container or shell like so:
celery -A invenio_app.celery beat -l INFO --scheduler invenio_jobs.services.scheduler:RunScheduler
The -l INFO flag sets the logging level to INFO. You can adjust the logging level (e.g., DEBUG, WARNING, ERROR) based on your needs, and the logs will reflect the level you set.
Note
Be sure to run this additional Celery beat scheduler in your production or deployed environments. Without it, scheduled and on-demand jobs will not be executed.
How to create a new job¶
This guide walks developers through implementing a new job using the engine provided by the invenio-jobs module. Jobs are asynchronous tasks that can be triggered from the admin UI or REST API. They run using Celery and support logging, argument validation, and result tracking.
Prerequisites¶
- Python development environment set up with InvenioRDM.
- Understanding of Celery tasks and entry points.
- Access to an InvenioRDM instance with administrator rights.
- A custom Celery scheduler beat process configured and running, which is required for executing both scheduled and manual jobs.
1. Define Your Celery Task¶
Create your actual business logic as a Celery task:
from celery import shared_task
from your_package import get_records_with_expired_embargoes, lift_embargo, reindex_records
@shared_task
def update_expired_embargoes(since=None, **kwargs):
"""Update and reindex records with expired embargoes."""
records = get_records_with_expired_embargoes(since)
for record in records:
lift_embargo(record)
reindex_records(records)
Error Handling and Logging¶
- Use
current_app.loggerfor logs visible in the UI. - Raise
TaskExecutionPartialErrorto mark a job as partially successful.
from invenio_jobs.errors import TaskExecutionPartialError
raise TaskExecutionPartialError("Processed 80%, 10 records failed.")
2. Create a Job Class¶
Use JobType to define a job that wraps your task. This crucial step ensures that your task appears as an selectable option when you choose what job to run within the UI.
You can inherit directly or use the create() helper.
from invenio_jobs.jobs import JobType
class UpdateEmbargoesJob(JobType):
id = "update_expired_embargoes"
title = "Update expired embargoes"
description = "Lift and reindex expired embargoes."
task = update_expired_embargoes
@classmethod
def build_task_arguments(cls, job_obj, since=None, **kwargs):
return {"since": since}
To include custom fields in the admin form, define a Marshmallow schema:
from marshmallow import fields, validate
from invenio_jobs.jobs import PredefinedArgsSchema
class ExportEmbargoSchema(PredefinedArgsSchema):
dry_run = fields.Boolean(
required=False,
missing=False,
metadata={"description": "If true, no changes will be persisted."}
)
class UpdateEmbargoesJob(JobType):
id = "update_expired_embargoes"
title = "Update expired embargoes"
description = "Lift and reindex expired embargoes."
task = update_expired_embargoes
arguments_schema = ExportEmbargoSchema
@classmethod
def build_task_arguments(cls, job_obj, since=None, dry_run=False, **kwargs):
return {
"since": since,
"dry_run": dry_run
}
3. Register Your Job and Task¶
In your project file, register the task and job using entry points:
[project.entry-points."invenio_celery.tasks"]
mysite_tasks = "mysite.tasks"
[project.entry-points."invenio_jobs.jobs"]
update_expired_embargoes = "mysite.jobs:UpdateEmbargoesJob"
[options.entry_points]
invenio_celery.tasks =
mysite_tasks = mysite.tasks
invenio_jobs.jobs =
update_expired_embargoes = mysite.jobs:UpdateEmbargoesJob
Tip
Note (local development only): If you're developing locally and have modified pyproject.toml/setup.cfg, remember to re-run pip install -e ./site (preceded by uv run or pipenv run as appropriate) so that entry point changes take effect.
4. Run and Monitor Jobs¶
Once your instance is restarted:
- Navigate to the Admin Panel → Jobs.
- Click Create Job and fill in the fields:
- Title and description.
- Select the task (e.g.
Update Expired Embargoes). - Choose the queue (a default queue should exist if jobs are enabled).
- After saving, you can trigger the job immediately or schedule it.
- You can also inspect previous runs and access detailed logs.
Tips¶
- Make your tasks idempotent if they might be run concurrently.
- Jobs and their runs are stored in the database, with status, arguments, and logs recorded for traceability.
- Admins only: only superusers can run jobs.
- See Job system design for an explanation of how the system works internally.
Email Notification Templates¶
Job notification emails use Jinja2 templates that can be customized to match your instance's branding and requirements. The templates are designed to be user-friendly and provide clear information about job execution outcomes.
Available Templates¶
The notification system uses three templates:
invenio_jobs/emails/base.html- Base email template with header and footerinvenio_jobs/emails/run_notification.html- HTML email body for job run notificationsinvenio_jobs/emails/run_notification.txt- Plain text email body for job run notifications
Customizing Templates¶
To customize the email templates for your instance, override them in your instance's templates directory:
-
Create the templates directory structure in your instance:
mkdir -p templates/semantic-ui/invenio_jobs/emails -
Copy the templates you want to customize from the
invenio-jobsmodule to your instance templates directory. -
Modify the templates to match your instance's branding, adding custom styling, logos, or additional information as needed.
Template Context¶
The notification templates receive the following context variables:
job- The Job object containing job metadata (name, description, etc.)run- The JobRun object with execution details (status, started_at, finished_at, etc.)config- Application configuration for accessing site settingsadmin_url- Direct link to view the run details in the admin panel
Example Customization¶
Here's an example of how to customize the HTML notification template:
{% extends "invenio_jobs/emails/base.html" %}
{% block content %}
<div style="padding: 20px;">
<h2>Job Run Notification: {{ job.title }}</h2>
<p>The job "{{ job.title }}" has completed with status:
<strong style="color: {% if run.status == 'SUCCESS' %}green{% else %}red{% endif %};">
{{ run.status }}
</strong>
</p>
<p>Started: {{ run.started_at }}</p>
<p>Finished: {{ run.finished_at }}</p>
<p><a href="{{ admin_url }}">View full details in admin panel</a></p>
</div>
{% endblock %}
Info
For information on how to configure job notifications, see Job Notifications.