Reactive Timer Microservice with Java Quartz, DynamoDB and Quarkus.

Before continuing with our frontend counterpart, let’s talk about backend microservices on AWS. As I mentioned in past articles, I have been working on a personal initiative for an IoT platform for Smart Cities. I want to share an exciting service that allows us to create scheduled tasks programmatically using Java Quartz. With this service in mind, imagine that you want to create a timed task to turn on a garbage collector robot at a particular hour of the day and over specific days of the week. Interesting right?! Let’s begin this article by creating our microservice with the mentioned technologies. Then, in the following article, we will be deploying this microservice on AWS using the ECS Fargate with a native Docker image.
To complete this guide, you need:
- GraalVM with Java 17, and corresponding
JAVA_HOME
andGRAALVM_HOME
configured appropriately. - Apache Maven 3.8.1 or superior.
- An IDE like IntelliJ or Eclipse.
- An AWS account to access the DynamoDB service.
NOTE: You can download the project repository from my GitHub account by following the instructions below.
The following command creates the Task table on your configured DynamoDB account:
# aws dynamodb create-table --table-name Task \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
Then, it is time to create our new CRUD project with the following maven command and open it with our favourite IDE:

First, create our Task entity:
@RegisterForReflection
public class Task {
private String id;
private String name;
private Integer hour;
private Integer minute;
private List<String> daysOfWeek;
private String executionCommand;
private ZonedDateTime executeUntil;
private String description;
private ZonedDateTime createdAt;
private ZonedDateTime updatedAt;
...
}
NOTE: The “@RegisterForReflection” annotation instructs Quarkus to keep the class and its members during the native compilation.
Create an abstract Task Service that contains helper methods that build DynamoDB requests for CRUD operations on the Task table:
public abstract class AbstractTaskService {
protected ScanRequest scanRequest() {
...
} protected GetItemRequest getItemRequest(String id) {
...
} protected PutItemRequest getPutItemRequest(Task task) {
...
} protected UpdateItemRequest getUpdateItemRequest(
Task actualTask, Task updatedTask) {
...
} protected DeleteItemRequest getDeleteItemRequest(Task task) {
...
}
}
We can use the asynchronous programming model supported currently in the AWS SDK version 2 in conjunction with the Mutiny library to interact with our Task table in a Reactive fashion:

All these operations must also create Quartz Jobs that must be executed automatically on a specific day and time indicated in the Task object:

Now it’s time to create our async REST resource component that consumes CRUD service methods in an async fashion:

Note that I’m omitting a lot of code in the previous images. You can find more code like validations, exception handling, utility classes, etc., in my project repository on GitHub.
To use async HTTP calls to interact with DynamoDB, we need the NIO client dependency in our Maven POM:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
</dependency>
To conclude this part, the final component that I want to show you is the class that executes the job operation. This class must contain the business logic performed during job execution. Here you can interact with other microservices in your architecture or interact with predefined services like AWS SQS to send a message that other software components must consume in an Event-Driven Architecture fashion:
public class TaskJob implements Job {
@Override
public void execute(JobExecutionContext executionContext) {
LOGGER.debug("execute() - START");
/* Your business logic */
LOGGER.debug("execute() - END");
}
}
It’s time to deploy our microservice locally; you only need to execute the following command to start our Quarkus application:
# mvn clean package
# java -jar target/quarkus-app/quarkus-run.jar

I used the Postman tool to consume the REST methods of the microservice. Let’s begin with the easiest, the POST method:

I created a task that must be executed on Monday, Wednesday and Saturday at 21:15. This task, when completed, must run the command indicated in the “executionCommand” field. As I mentioned at the beginning of this article, this task simulates the activation of a garbage collector robot managed by an IoT Platform that I’m constructing on AWS. Then, our following method to consume is a GET operation:

Here you see that I’ve created 2 tasks. The last one must be executed on Wednesdays and Fridays at 20:00. When I’m writing these lines, it is Wednesday night. When the time comes to accomplish this task, the following lines will be printed in our terminal:

In the previous image, you see the “execute” method of the “TaskJob” class that I described before. Note that the date-time shown in the picture shows the 20:00 hours. Let’s update the Task configured to be performed at 21:15 so it executes earlier.

I updated the “daysOfWeek” field and the “hour” and “minute” too, so now our task will run at 20:05. If we execute the GET method again, we will see our updated task:

This update includes the modification of the Quartz Jobs associated with the task. We need to interact with the Quartz context to update the trigger object associated with the actual job. For this reason, our task now executes at the edited time. You can see more details in the project’s source code.

If we go to the DynamoDB console, we will see our 2 tasks; one of them with the updated fields:

Finally, it’s time to show the DELETE method operation. Now I want to delete one of the tasks, and this is the result:


As we see, there is only one task. If we go to the DynamoDB console, we must see the remaining task:

And that’s it!! I’ve created a bash file that compiles and packages the entire project. I also created a script that creates the Task table on DynamoDB. You only need to run the following command at the project’s root folder:
# ./run-scripts.sh
The following article will show you how to deploy this microservice on AWS ECS with Fargate (serverless style). For this purpose, we will be creating the container image for this microservice with Docker, but using the native image of the same with the help of the Quarkus technology.
Thanks for reading, and I will see you in my next post.