Building Simple Dapr Cron Jobs with ASP.NET Core Web APIs
Will Velida
Posted on June 20, 2023
I've been thinking about migrating one of my side projects from Azure Functions to the Dapr framework to make it more portable. One of the most important components of this architecture is the ability to refresh an authentication token that enables each Function app to retrieve data from an external API. In an Azure Functions architecture, we can use timer triggers to perform scheduled jobs simply.
The issue here is that Functions have an opinionated programming model. While this does make integrations between components simple, this can lock us into the Azure Functions hosting model, limiting the portability that I'd like my architecture to achieve.
The Dapr framework provides bindings that support cron jobs. Cron jobs uses a configurable interval schedule to trigger our application. This is great for performing scheduled tasks, such as background jobs or cleanup work that needs to be performed at a regular interval.
This article is going to cover how to configure a basic Dapr cron job in a ASP.NET Web API. I'll cover how to set up a cron binding component, configure the Web API to subscribe to the cron binding and then finally, run it to see it in action.
This sample is going to be super simple, so don't expect it to break the internet (or whatever the kids are saying these days). We're just here to see how Dapr cron jobs work at a basic level. If you want to follow along with the full code sample used in this article, check out my GitHub.
Let's dive in! 🚀
Setting up our Cron Job
To set up our Cron Job, we create a YAML file with the following content:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: SayHello
spec:
type: bindings.cron
version: v1
metadata:
- name: schedule
value: "@every 10s"
scopes:
- say-hello
Let's break down the important parts here:
- The
bindings.cron
type specifies that we are defining a Dapr cron job. - In the top level
metadata
property, we give our component a name ofSayHello
. We need the endpoint of our ASP.NET Web API controller to match the name of this component, so we'll remember that for later. - In the
spec
block, we're defining a schedule to run this Cron Job every 10 seconds.
Dapr Cron binding supports the following formats:
Character | Descriptor | Acceptable Values |
---|---|---|
1 | Second | 0 to 59, or * |
2 | Minute | 0 to 59, or * |
3 | Hour | 0 to 23, or * (UTC) |
4 | Day of the month | 1 to 31, or * |
5 | Month | 1 to 12, or * |
6 | Day of the week | 0 to 7 (where 0 and 7 represent Sunday), or * |
So you could have the following cron jobs defined like so:
-
30 * * * * *
- every 30 seconds -
CRON_TZ=America/New_York 0 30 04 * * *
- every day at 4:30am New York time
Dapr also supports shortcuts. So in my components, I've used @every 10s
to run our Cron Job every 10 seconds. You can also use @daily
or @hourly
for daily and hourly jobs.
To learn more about the Cron binding spec in Dapr, check out the documentation.
Configuring our Web API as a Cron Job
Lets set up our Web API that will run on a schedule:
using Dapr.Client;
using Microsoft.AspNetCore.Mvc;
namespace SayHello.Api.Controllers
{
[Route("SayHello")]
[ApiController]
public class HelloController : ControllerBase
{
private readonly ILogger<HelloController> _logger;
private readonly DaprClient _daprClient;
public HelloController(ILogger<HelloController> logger, DaprClient daprClient)
{
_logger = logger;
_daprClient = daprClient;
}
[HttpPost]
public IActionResult Post()
{
_logger.LogInformation($"Hello Dapr Cron Job! The time is {DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss")}");
return Ok();
}
}
}
This is just a basic API controller that we've defined here. The important point here is that we've given our Route
the name SayHello. This matches the name of our component of our Cron job that we defined earlier.
With that defined, our endpoint that we will listen to matches the name of the component of the Cron job. We then set up a POST request that logs a message to the console every 10 seconds by the Dapr sidecar.
Even though we aren't using the DaprClient in our code, we'll need to install it in our Web API project and then register the service in our Program.cs
file like so:
// Program.cs - Rest of file left out for brevity.
// Add services to the container.
builder.Services.AddDaprClient();
builder.Services.AddControllers();
If you don't install the Dapr.AspNetCore
package, the API won't be able to subscribe to the Cron binding that we've defined earlier.
Running our Cron Job
To run our cron job, we can run it using the Dapr CLI:
dapr run --app-id say-hello --app-port 7042 --dapr-http-port 3500 --app-ssl --resources-path ../../../components/ -- dotnet run --launch-profile https
I've given my Dapr application an id of say-hello
. The --app-port
is the HTTPS port of my ASP.NET Web API found in my launchSettings.json
file and the --resources-path
parameter is pointing to the directory that my cron binding YAML component file is stored.
Once we've run our Dapr CLI command, we should see our message being logged to the console every 10 seconds like so:
Conclusion
In this article, I talked about how we can use cron jobs in Dapr to run applications on a schedule, such as background workers or cleanup jobs. I showed you how you can configure your Cron job as a YAML component, wire it up to a ASP.NET Core Web API and then we ran our cron job to see it in action.
In the future, I'll be looking to build something a little more complex using Dapr cron jobs. Once I've got something cool to share, I'll let you y'all know! 😀
If you want the full code sample used in this article, check out my GitHub.
If you have any questions on the above, feel free to reach out to me on twitter @willvelida
Until next time, Happy coding! 🤓🖥️
Posted on June 20, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.