Event Schedulers

This section will proceed with a suggested course of action when utilizing the EventScheduler for dealing with deadlines.

To help understand this better lets take the scenario of a saga: It is easy to make a saga take action when something happens. After all, there is an event to notify the saga. That said, what if you want your saga to do something when nothing happens? That’s what deadlines are used for. For invoices, that is typically several weeks, whereas the confirmation of a credit card payment should occur within a few seconds.

Scheduled events as deadlines

In Axon, you can use an EventScheduler to schedule an event for publication. In the example of an invoice, you would expect the invoice to be paid within thirty days. A saga would, after sending the CreateInvoiceCommand, schedule an InvoicePaymentDeadlineExpiredEvent to be published in 30 days. The EventScheduler returns a ScheduleToken after scheduling an event. This token can be used to cancel the schedule, for example when a payment of an Invoice has been received.

Axon provides four EventScheduler implementations:

It is important to note that the JubRunrEventScheduler, QuartzEventScheduler, AxonServerEventScheduler and DbSchedulerEventSerializer all should use the event Serializer to serialize and deserialize the scheduled event. If the Serializer used by the scheduler does not align with the Seralizer used by the event store, exceptional scenarios should be expected. The Quartz implementation’s Serializer can be set by defining a different EventJobDataBinder, whereas the JobRunr, Axon Server and db-scheduler implementations allows defining the used Serializer directly through the builder.

One or more components will be listening for scheduled Events. These components might rely on a transaction bound to the thread that invokes them. Scheduled events are published by threads managed by the EventScheduler. To manage transactions on these threads, you can configure a TransactionManager or a UnitOfWorkFactory that creates a transaction bound unit of work.

Simple event scheduler

The pure-Java implementation of the EventScheduler uses a ScheduledExecutorService to schedule event publication. Although the timing of this scheduler is highly reliable, it is a pure in-memory implementation. Once the JVM is shut down, all schedules are lost. This makes this implementation unsuitable for long-term schedules. The SimpleEventScheduler needs to be configured with an EventBus and a SchedulingExecutorService (see the static methods on the java.util.concurrent.Executors class for helper methods).

JobRunr event scheduler

The JobRunrEventScheduler is a more reliable and enterprise-worthy implementation based on JobRunr. It offers several ways to persist the scheduled jobs, and has good integration with Spring Boot. Using JobRunr as underlying scheduling mechanism, it provides more powerful features, such as clustering, misfire management as well as an optional dashboard. This means event publication is guaranteed. It might be a little late, but it will be published. JobRunr supports both SQL and some NoSQL databases. It needs to be configured with a JobRunr JobScheduler, an EventBus and a Serializer.

Db-scheduler event scheduler

The DbSchedulerEventScheduler is similar in convenience compared to the JobRunr- and the Axon Server EventScheduler implementations, based on the db-scheduler project. It offers several ways to persist the scheduled jobs, and has good integration with Spring Boot. It’s pretty simple, as it only needs one table. For most sql databases the sql to set the table is available

Compared to JobRunr, it lets you set a poll interval for new tasks more freely. Another advantage compared to JobRunr is that adding a task will become part of the current transaction when a TransactionManager is set. The biggest things missing compared to JobRunr are a dashboard, and support for multiple NoSQL databases. The DbSchedulerEventScheduler needs to be configured with a db-scheduler Scheduler, an EventBus, and a Serializer.

The data for an event can be serialized in either a binary format or in a human-readable format. Switching between these formats is done via the useBinaryPojo property on the scheduler’s builder. Depending on this property, the correct task should be added in the constructor of the Scheduler.

Axon Server event scheduler

The AxonServerEventScheduler uses Axon Server to schedule events for publication. As such, it is a hard requirement to use Axon Server as your Event Store solution to utilize this event scheduler. Just as the QuartzEventScheduler, the AxonServerEventScheduler is a reliable and enterprise-worthy implementation of the EventScheduler interface. Creating a AxonServerEventScheduler can be done through its builder, whose sole requirement is the AxonServerConnectionManager.

Quartz event scheduler

The QuartzEventScheduler is an alternative enterprise-worthy implementation based on Quartz, but the project has not seen much recent activity. Using Quartz as underlying scheduling mechanism, it provides features, such as persistence, clustering and misfire management. It needs to be configured with a Quartz Scheduler and an EventBus. Optionally, you may set the name of the group that Quartz jobs are scheduled in, which defaults to "AxonFramework-Events".

Spring configuration

Spring users can use the QuartzEventSchedulerFactoryBean or SimpleEventSchedulerFactoryBean for easier configuration. It allows you to set the PlatformTransactionManager directly. Spring Boot users which rely on Axon Server do not have to define anything. The auto-configuration will automatically create a AxonServerEventScheduler for them.

Spring Boot users who want to use the JobRunr event scheduler can add jobrunr-spring-boot-starter as a dependency. In addition, an EventScheduler bean configuration needs to be added. This should look like:

@Bean
public EventScheduler eventScheduler(
        @Qualifier("eventSerializer") final Serializer serializer,
        final JobScheduler jobScheduler,
        final EventBus eventBus,
        final TransactionManager transactionManager,
        final Spanfactory spanfactory
) {
    return JobRunrEventScheduler.builder()
            .jobScheduler(jobScheduler)
            .serializer(serializer)
            .eventBus(eventBus)
            .transactionManager(transactionManager)
            .spanFactory(spanfactory)
            .build();
}

For both JobRunr and db-scheduler, auto-configuration is included via the axon-spring-boot-starter. This means that if you don’t have an EventScheduler configured in the application, but you do have a JobScheduler bean (in the case of JobRunr) or a Scheduler bean (in the case of db-scheduler), an EventScheduler will be auto-configured for you. In these cases, it is recommended to set the axon.axonserver.enabled property to false to prevent the creation of the AxonServerEventScheduler.