Skip to main content

Timer Job Service

The TimerJobService allows you to schedule events on a specific timestamp. It is implemented using the TimerJob dataElement which must be enabled through the #processAutomation.timerJob tag or the following option:

Option
processAutomation.TimerJob.enable ApplicationApplicationInstance

Enables the expansion of the TimerJob element and the corresponding TimerJobService.

<options>
<processAutomation.TimerJob.enable/>
</options>

The easiest way to use the service is through the TimerField Trigger which schedules a transition when the timestamp in a field is reached.

The service can be consumed directly as well, which the remainder of this article will be about.

Database migration

The timer job service requires a database table to operate. Since this is an optional feature, you may need to migrate when enabling it.

add_timer_job_service.sql (postgres)
-- > TimerJob
CREATE TABLE PROCESS_AUTOMATION.TimerJob (
id BIGINT NOT NULL,
key VARCHAR(255),
payload VARCHAR(16384),
status VARCHAR(255),
timestamp TIMESTAMP,
type VARCHAR(255),
PRIMARY KEY (id)
);
-- < TimerJob

Using the service

To start using the service it needs to be injected as an EJB.

@EJB
TimerJobService timerJobService;

void scheduleTask(Context context) {
TimerJob job = TimerJob
.data("my-timer-type", "data")
.keyed("my-job")
.on(Instant.now().plusSeconds(120));
this.timerJobService.schedule(job, context);
}

This snippet already shows most of the API. A TimerJob has the following properties:

  • type (String) An identifier on which can be decided how to handle the TimerJob.
  • data (Object) The data object. Must be jackson serializable.
  • key (String) The key of the timer. If two timers with the same key are scheduled, the first one is cancelled. If no key is provided, a UUID will be used as the key.
  • timestamp (Instant/Date) The moment the timer should go off. If no timestamp is provided, it will be scheduled immediately.

Once the timer goes off, a TimerJobEvent is fired which can be handled in any way you like.

void onTimer(@Observes TimerJobEvent event) {
if (event.type().equals("my-timer-type")) {
System.out.println(event.payload()); // > "data"
}
}

Dispatching events with callback

To make using the service even easier and type-safe, you can also define your own event classes. Note that these must also be (de)serializable by jackson!

@EJB
TimerJobService timerJobService;

record MyEvent(String name) {}

void scheduleEvent(Context context) {
TimerJob job = TimerJob
.event(new MyEvent("event"))
.on(Instant.now().plusSeconds(30));
this.timerJobService.schedule(job, context);
}

void onEvent(@Observes MyEvent event) {
System.out.println(event.name()); // > event
}

This makes it really easy to implement functionality which must happen at a very specific moment in time.

Under the hood the event will be encoded using it's qualified type as the type, and the event object itself as the data. A standard TimerJobEventRouter is provided to try and deserialize the TimerJobEvent using the given type. If that succeeds the event will be fired.