Recurrent Workflows With Cloud Native Dapr Jobs
Workflow scheduling is something we see often. As part of this article, we will look at how Dapr Jobs helps to easily run periodic workloads.
Join the DZone community and get the full member experience.
Join For FreeWe have been learning quite a lot about Dapr now.
These are some of my previous articles about Dapr Workflows and Dapr Conversation AI components. Today, we will discuss Jobs, another important building block of the Dapr ecosystem.
Many times, you will need to run workflows on a schedule. For example,
- Regular file backups: Periodic backups help restore data when there is a failure. So, you could schedule one to back up your data on a regular basis.
- Performing maintenance tasks: Things like file cleanups, recycling VM nodes, and batch processing data are some other scenarios where Dapr Jobs can help.
Jobs Architecture
- MyApp is the Java application we will be creating today, responsible for scheduling and registering the job.
- When creating the cron job, the application needs to register a callback endpoint so that the Dapr runtime can invoke it at the scheduled time.
- The endpoint should be a POST request with a URL pattern similar to
/jobs/{jobName}
, where jobName corresponds to the name used when registering the job.
- The endpoint should be a POST request with a URL pattern similar to
Now, let's look at a practical demonstration. In the sample app, we will create a simple job that runs every 10 seconds. The callback URL registered will print the name of the job that is being invoked.
Because we have used .NET SDK in all the previous articles, this time we will go with the java-sdk.
Step 1
Download the Dapr CLI and install it. There is also an MSI that you could use to install the latest version here: https://github.com/dapr/cli/releases.
powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"
Step 2
Verify the installation using the following command.
dapr -h
Make sure you have Docker running too because the cli downloads docker images of runtime, scheduler and placement services.
Next, it is time to set up the app. For this, we will create a maven project and use the dapr maven dependencies. Gradle could be another choice.
Step 3
Create a Maven project. Add the following Dapr dependency to it.
<dependency>
<groupId>io.dapr</groupId>
<artifactId>dapr-sdk</artifactId>
<version>${project.version}</version>
</dependency>
We also discussed registering an endpoint that the scheduler could call. In this case, we are using the Spring framework to register an endpoint. You could also use JAX-RS or any other framework of your choice.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot.version}</version>
</dependency>
Step 4
App logic to register the job.
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.DaprPreviewClient;
import io.dapr.client.domain.GetJobRequest;
import io.dapr.client.domain.GetJobResponse;
import io.dapr.client.domain.JobSchedule;
import io.dapr.client.domain.ScheduleJobRequest;
import io.dapr.config.Properties;
import io.dapr.config.Property;
import java.util.Map;
public class DemoJobsClient {
/**
* The main method of this app to register and fetch jobs.
*/
public static void main(String[] args) throws Exception {
Map<Property<?>, String> overrides = Map.of(
Properties.HTTP_PORT, "3500",
Properties.GRPC_PORT, "51439"
);
try (DaprPreviewClient client = new DaprClientBuilder().withPropertyOverrides(overrides).buildPreviewClient()) {
// Schedule a job.
System.out.println("**** Scheduling a Job with name dapr-jobs *****");
ScheduleJobRequest scheduleJobRequest = new ScheduleJobRequest("dapr-job",
JobSchedule.fromString("*/10 * * * * *")).setData("Hello World!".getBytes());
client.scheduleJob(scheduleJobRequest).block();
System.out.println("**** Scheduling job with name dapr-jobs completed *****");
// Get a job.
System.out.println("**** Retrieving a Job with name dapr-jobs *****");
GetJobResponse getJobResponse = client.getJob(new GetJobRequest("dapr-job")).block();
// Delete a job.
DeleteJobResponse deleteJobResponse = client.deleteJob(new DeleteJobRequest("dapr-job")).block();
}
}
}
- We have created a simple Java class with a main method. Because Jobs is still a preview feature,
DaprPreviewClient
is used to schedule, get, or delete a Job. - The
ScheduleJobRequest
constructor takes in two parameters, the name of the job and the cron expression, which in this case is to run every 10 seconds. - Finally, we call the
scheduleJob()
method that will schedule a job with the Dapper runtime. - The
getJob()
method is used to retrieve the job details of an existing job.
Step 5
Register a callback endpoint.
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
/**
* SpringBoot Controller to handle jobs callback.
*/
@RestController
public class JobsController {
/**
* Handles jobs callback from Dapr.
*
* @param jobName name of the job.
* @param payload data from the job if payload exists.
* @return Empty Mono.
*/
@PostMapping("/job/{jobName}")
public Mono<Void> handleJob(@PathVariable("jobName") String jobName,
@RequestBody(required = false) byte[] payload) {
System.out.println("Job Name: " + jobName);
System.out.println("Job Payload: " + new String(payload));
return Mono.empty();
}
}
Once it is time to run the scheduled job, the Dapr runtime will call the following endpoint. You could define a PostMapping with the specific Job name like "/job/dapr-job" or use a path param like we did above.
Step 6
Write the startup file for the Spring Boot app.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Spring Boot application to demonstrate Dapr Jobs callback API.
* <p>
* This application demonstrates how to use Dapr Jobs API with Spring Boot.
* </p>
*/
@SpringBootApplication
public class DemoJobsSpringApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(DemoJobsSpringApplication.class, args);
}
}
Step 7
Now, it is time to run the application. Go to the Maven project folder and run the following command. Change the name of the jar and class if required.
dapr run --app-id myapp --app-port 8080 --dapr-http-port 3500 --dapr-grpc-port 51439 --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsSpringApplication
Output from the command.
Step 8
Finally, run the DemoJobsClient
.
java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.jobs.DemoJobsClient
Output from the command.
**** Scheduling a Job with name dapr-jobs *****
Switching back to the other window where we ran the command from Step 8, you will notice the following console log.
== APP == Job Name: dapr-job
== APP == Job Payload: Hello World!
Conclusion
Dapr Jobs is a powerful tool that can help you schedule workloads without having to take the complexity of using CRON libraries. Go try it out.
Opinions expressed by DZone contributors are their own.
Comments