Skip to content

Scheduled jobs

engine-jobs runs scheduled work on a Quartz scheduler. There are two ways to declare a job: the legacy .job artefact (JSON descriptor) and the modern @Scheduled decorator / annotation.

.job artefact

A JSON descriptor under the project points at a JS/TS/Java handler module and supplies a cron expression. JobSynchronizer reconciles each .job file into a Quartz trigger.

json
{
  "name": "demo-job",
  "group": "demo",
  "expression": "0 0 * * * ?",
  "handler": "demo/jobs/nightly.js",
  "description": "Run every hour"
}

Stop / start / reschedule from the Jobs perspective.

@Component job

The modern approach is a @Component bean. There are exactly two styles. A class uses one or the other, never both - the engine rejects a class that mixes them.

Java

Style 1 - self-describing interface. A @Component that implements JobHandler. The interface carries the binding itself: cron() returns the schedule and run() does the work, so no class-level @Scheduled is used. This mirrors Spring's org.quartz.Job.

java
package demo.scheduled;

import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.job.JobHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class CleanupJob implements JobHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger("app.out");

    @Override
    public String cron() {
        return "* * * * * ?";
    }

    @Override
    public void run() {
        LOGGER.info("CleanupJob executed!");
    }
}

Style 2 - method-level @Scheduled. @Scheduled(expression = "…") on a public no-arg method of a @Component (Spring @Scheduled style), so a single bean can hold several jobs alongside other logic and inject collaborators:

java
package demo.scheduled;

import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.job.Scheduled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class Maintenance {

    private static final Logger LOGGER = LoggerFactory.getLogger("app.out");

    @Scheduled(expression = "0/45 * * * * ?")
    public void purgeTempFiles() {
        LOGGER.info("Maintenance.purgeTempFiles executed (method-level @Scheduled)!");
    }
}

Both styles give compile-time signature checking and a direct dispatch path. There is no reflective by-name fallback. See /sdk/job/decorators for details.

Sample project: dirigiblelabs/sample-java-job-decorator - CleanupJob (interface style, fires every second) and Maintenance (method-level @Scheduled). SDK reference: /sdk/.

TypeScript:

ts
import { Scheduled } from "@aerokit/sdk/job";

@Scheduled({ expression: "0 0 * * * ?" })
export class NightlyJob {

  public run() {
    // work here
  }
}

The expression is a standard Quartz cron string.

Lifecycle

Hot-reload reinstalls the schedule on every change - rewriting the cron expression updates the trigger on the next synchronization cycle. Deleting the file removes the trigger.

Operating the schedule

The Jobs perspective in the IDE shows every active job: state, next fire time, last result. Pause, resume, and trigger-now controls are there too. See /help/ide/perspectives/jobs.

For runtime control from code, use the @aerokit/sdk/job/scheduler module.

Tenancy

Scheduled jobs are tenant-isolated - the same .job file under one project runs once per tenant.

See also

Released under the EPL-2.0 License.