Skip to main content
System administrator Developer Jahia 8.2

How do I change the schedule of a built-in Jahia job, and can I stop one that is running?

Question

How do I change the schedule of a built-in Jahia job, and can I stop one that is running?

Answer

Changing the cron of a built-in job

There is no jahia.properties key for it. Built-in job schedules are defined in Spring XML, and the cron expression is a literal, not a ${...} placeholder. Taking DataStoreGarbageCollectorJob as the example, in applicationcontext-scheduler-jobs.xml:

<bean id="DataStoreGarbageCollectorJob" parent="jobSchedulingBean" lazy-init="true">
    <property name="jobDetail">
        <bean class="org.springframework.scheduling.quartz.JobDetailBean">
            <property name="name" value="DataStoreGarbageCollectorJob"/>
            <property name="group" value="Maintenance"/>
    ...
    <property name="trigger">
        <bean class="org.quartz.CronTrigger">
            <property name="name" value="DatastoreGarbageCollectorTrigger"/>
            <property name="cronExpression" value="0 0 0 1 * ?"/>

So the default is the 1st of each month at midnight.

To change it, drop a Spring override file into <JAHIA_HOME>/digital-factory-config/jahia/, matching applicationcontext-override-*.xml, redefining the bean with the same id and your cron.

Keeping the id matters. Jahia instantiates this bean by name at startup (applicationContext.getBean(dataStoreGarbageCollectorBeanId)), so renaming it means the job is simply never scheduled - silently.

Yes, the change applies on restart - even in production mode

A common assumption is that overwriteExisting defaults to false outside development mode and therefore your edit is ignored. It is not. When the job is already stored, Jahia calls syncJobTriggers(), which compares the cron expressions and reschedules when they differ:

if (!newCron.equals(existingCron)) {
    ...
    updateTrigger(newTrigger);
}

Keep the trigger name identical too. Triggers are matched by full name, so renaming the trigger unschedules the old one and creates a new one instead of rescheduling - which works, but discards the trigger's existing state.

Watch the spelling: the job is DataStoreGarbageCollectorJob (capital S) and the trigger is DatastoreGarbageCollectorTrigger (lowercase s). They differ.

Turning a job off instead

The parent bean accepts <property name="disabled" value="true"/>.

Reaching the scheduler from code

SchedulerService schedulerService = ServicesRegistry.getInstance().getSchedulerService();

org.quartz.Scheduler persistent = schedulerService.getScheduler();     // JDBC-backed
org.quartz.Scheduler ram        = schedulerService.getRAMScheduler();  // in-memory

There really are two schedulers. Persistent jobs survive a restart and run only on a processing server; RAM jobs do not survive and run anywhere.

getScheduler() does not hand you the raw Quartz object - verified on a running 8.2.3.2, it returns a ReadOnlyModeAwareScheduler wrapper that refuses mutating calls while the platform is in read-only mode. getRAMScheduler() returns the unwrapped StdScheduler.

Reading the live triggers on a stock 8.2.3.2 gives, for example:

SchedulerTriggerCronJob
persistentDEFAULT/DatastoreGarbageCollectorTrigger0 0 0 1 * ?Maintenance/DataStoreGarbageCollectorJob
persistentDEFAULT/ContentHistoryPurgeTrigger0 0 0 L DEC ? *Maintenance/ContentHistoryPurgeJob
persistentDEFAULT/JobHistoryPurgeTrigger0 0 * * * ?Maintenance/JobHistoryPurgeJob
ramDEFAULT/EvictExpiredHTMLCacheKeyTrigger0 0/15 * * * ?Maintenance/EvictExpiredHTMLCacheKeyJob

Note the trigger group is DEFAULT while the job group is Maintenance - another easy mistake when calling the Quartz API, which takes the trigger's group for trigger operations.

Can I force-stop a running job? No

Jahia's BackgroundJob implements org.quartz.StatefulJob, not org.quartz.InterruptableJob. Checked live on 8.2.3.2:

InterruptableJob.class.isAssignableFrom(BackgroundJob.class)  ->  false

InterruptableJob appears nowhere in Jahia core, and nowhere in Jahia's public GitHub organisation. Scheduler.interrupt(...) exists on the API but cannot interrupt a job class that does not implement that interface.

What you can do affects future runs only:

GoalCall
Stop it running againunscheduleJob(triggerName, triggerGroup)
Remove the job entirelydeleteJob(jobName, jobGroup)
Suspend / resumepauseJob(...) / resumeJob(...)
Run it right nowtriggerJobWithVolatileTrigger(...)

None of these stop a thread already inside the job. The only way to stop an in-flight background job is to restart the node - and even then Jahia is configured to wait for running jobs to finish on shutdown.

For the DataStore GC specifically, the work happens inside Jackrabbit's mark/sweep, which Jahia could not interrupt even if the job class allowed it.

The jobs admin page

The job list lives in the Tools module, not in the Administration UI: <host>/tools/jobadmin.jsp, with ?schedulerType=ram for the RAM scheduler. It shows each job's trigger and cron and offers trigger-now, pause, resume, unschedule and delete - but no edit-cron and no kill, consistent with the above.


This article was drafted with AI assistance, then reviewed and curated by Jahia Customer Support engineers before publication.