Configuring Quartz Deadlines in Axon Framework
Axon Framework is the best framework I know for implementation of CQRS/ES applications using JVM. I’m using it in both commercial and play projects and I love the way the abstractions are built.
One of the major design ideas of the framework is the separation of the business logic from the infrastructure configuration. This allows to implement the application starting with a trivial setup and migrate it later by providing a more complex infrastructure and deployment setup to a solid (if needed distributed) application. This feature affects almost everything: there is mostly a
Simple*Something implementation and some more you might choose from.
As I started with implementation of Sagas, I discovered the concept of DeadlineManagers provided by the Axon Framework. To put it simple, it is a way to model timed behavior inside of your application and to react on time passing.
Deadline Managers for Retrying
Let me give you an example. Imagine you are implementing a system that needs to use a protocol for communication to an external system. You want to decouple the command dispatching inside of your Aggregate from the actual communication and provide some means for retries, because the communication partner might have availability and / or response issues. Consider you set your Aggregate to the desired state, fire the corresponding event and start a Saga which is responsible to drive the protocol communication. The Saga would try to run the communication and either finish on successful communication or set-up a deadline for retry on any communication errors. On a retry, the Saga does the same, until the maximum number of attempts is reached.
If there is a client to call defined like this:
The Saga triggered by an event uses the protocol client and tries to invoke the remote system. In case of Success and Failure status it considers the protocol as completed, but in case of Error, it will go into retry mode. By doing so, it creates a new schedule using the provided DeadlineManager. After the time passes, the deadline gets triggered and can retry. Here is the corresponding snippet:
In addition to this code, you will need to provide a deadline manager configuration for your application. There is a
SimpleDeadlineManager implementation configured like this:
Since it works fine for some use cases, it lacks any support for persistence and is only working as long as the current JVM is running. This means, that if you restart your application your schedules are lost.
As usual, there is an alternative implementation for the DeadlineManager supporting Quartz Scheduler. To configure it in Spring-Boot you need several things:
- Add the dependency to
spring-boot-starter-quartzto your dependencies,
- Configure your Quartz Scheduler to use persistence,
- And finally, configure the
Configure Quartz Scheduler
I consider you have a RDBMS already configured in your application — for Saga persistence or for projections. In this case, it makes sense to use the same database for persistence of Quartz, since it supports JDBC-based persistence of schedules, triggers, jobs and everything it has. Please add the following options to your
Adopt the driverDelegateClass to your database platform — just check the classes in the package
org.quarzt.impl.jdbcjobstore to choose from. As you can see, I set the
initialize-schema property to
never, because I’m using Flyway for my database migrations. If you are looking for the SQL scripts, again check the
org.quarzt.impl.jdbcjobstore for contained SQL files and copy to the corresponding location. I also set-up the
startup-delay to avoid Quartz to start scheduling before the application is up and running.
Configure Quartz Deadline Manager
The configuration of the deadline manager is quite straight forward:
Axon Framework provides a great abstraction of time for implementation of time-dependent behavior like deadlines in your application. This integrates well with the other concepts of your CQRS/ES application like Aggregates and Sagas. The core infrastructure component for any deadline manipulations is the
DeadlineManager. Along with the
SimpleDeadlineManager used for trivial cases and toy projects (the name is not chosen random!) there is a more serious implementation providing an integration with an enterprise-ready Quartz scheduler.