The .NET Core CLI comes with tons of pre-built project templates! One of the new templates that will be included with .NET Core 3 will be for building worker services.
Combining .NET Core worker services with Coravel can help you build lightweight background job scheduling applications very quickly. Let's take a look at how you can do this in just a few minutes!
Note: Worker services are lightweight console applications that perform some type of background work like reading from a queue and processing work (like sending e-mails), performing some scheduled background jobs from our system, etc. These might be run as a daemon, windows service, etc.
Installing .NET Core 3 Preview
At the writing on this article, .NET Core 3 is in preview. First, you must install the SDK. You can use Visual Studio Code for everything else in this article 👍.
Coravel's Task Scheduling
Coravel is a .NET Core library that gives you advanced application features out-of-the-box with near-zero config. I was inspired by Laravel's ease of use and wanted to bring that simple and accessible approach of building web applications to .NET Core.
One of those features is a task scheduler that is configured 100% by code.
By leveraging Coravel's ease-of-use with the simplicity of .NET Core's worker service project template, I'll show you how easily and quickly you can build a small back-end console application that will run your scheduled background jobs!
Worker Service Template
First, create an empty folder to house your new project.
Then run:
dotnet new worker
Your worker project is all set to go! 🤜🤛
Check out Program.cs and you'll see this:
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
});
Configuring Coravel
Let's add Coravel by running dotnet add package coravel
.
Next, in Program.cs, we'll modify the generic code that was generated for us and configure Coravel:
public static void Main(string[] args)
{
IHost host = CreateHostBuilder(args).Build();
host.Services.UseScheduler(scheduler => {
// We'll fill this in later ;)
});
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddScheduler();
});
};
Since Coravel is a native .NET Core set of tools, it just works™ with zero fuss!
Adding An Invocable
One of Coravel's fundamental concepts is Invocables.
Each invocable represents a self-contained job within your system that Coravel leverages to make your code much easier to write, compose and maintain.
Next, then, create a class that implements Coravel.Invocable.IInvocable
:
public class MyFirstInvocable : IInvocable
{
public Task Invoke()
{
Console.WriteLine("This is my first invocable!");
return Task.CompletedTask;
}
}
Since we are going to simulate some async work, we'll just log a message to the console and then return Task.CompletedTask
to the caller.
Scheduling Your Invocable
Here's where Coravel really shines 😉.
Let's schedule our new invocable to run every 5 seconds. Inside of our Program.cs main method we'll add:
host.Services.UseScheduler(scheduler => {
// Yes, it's this easy!
scheduler
.Schedule<MyFirstInvocable>()
.EveryFiveSeconds();
});
Don't forget to register your invocable with .NET Core's service container:
.ConfigureServices(services =>
{
services.AddScheduler();
// Add this 👇
services.AddTransient<MyFirstInvocable>();
});
In your terminal, run dotnet run
.
You should see the output in your terminal every five seconds!
Real-World Invocable
Sure, writing to the console is great - but you are going to be making API calls, database queries, etc. after all.
Let's modify our invocable so that we can do something more interesting:
public class SendDailyReportEmailJob : IInvocable
{
private IMailer _mailer;
private IUserRepository _repo;
public SendDailyReportEmailJob(IMailer mailer, IUserRepository repo)
{
this._mailer = mailer;
this._repo = repo;
}
public async Task Invoke()
{
var users = await this._repo.GetUsersAsync();
foreach(var user in users)
{
var mailable = new DailyReportMailable(user);
await this._mailer.SendAsync(mailable);
}
}
}
Since this class will hook into .NET Core's service container, all the constructor dependencies will be injected via dependency injection.
If you wanted to build a lightweight background application that processes and emails daily reports for all your users then this might be a great option.
Configuring As A Windows Service
While beyond the scope of this article, you can take a look at how .NET Core 3 will allow configuring your worker as a windows service.
And, apparently, there's upcoming support for systemd too!
Conclusion
What do you guys think about .NET Core's worker services?
I find they are so easy to get up-and-running. Coupled with the accessibility designed into Coravel, I find these two make an awesome pair for doing some cool stuff!
All of Coravel's features can be used within these worker services - such as queuing tasks, event broadcasting, mailing, etc.
One thing I'd love to try is to integrate Coravel Pro with a worker service. One step at a time though 🤣.
Keep In Touch
Don't forget to connect with me on:
You can also find me at my web site www.jamesmichaelhickey.com.
Navigating Your Software Development Career Newsletter
An e-mail newsletter that will help you level-up in your career as a software developer! Ever wonder:
✔ What are the general stages of a software developer?
✔ How do I know which stage I'm at? How do I get to the next stage?
✔ What is a tech leader and how do I become one?
✔ Is there someone willing to walk with me and answer my questions?
Sound interesting? Join the community!
Top comments (12)
I really like the concept of Invocables! It keeps the code clean.
For scheduling I've always used hangfire, which works really well, but things can get messy really fast since scheduling in hangfire works with anonymous method invocation
Is there a way to update/cancel a scheduled task with Coravel (like in the above example where a
jobId
is returned?In my side project I'm currently using hangfire, but Coravel looks a lot cleaner and I've already wondered how I can clean up these hangfire invocations.
Hangfire is def the defacto right now. Coravel was never built as a direct alternative, but many have pointed out that it's much easier to use.
Also, Coravel supports true async jobs, whereas Hangfire doesn't actually support true async jobs. So all that I/O in your background jobs will actually block your threads 🤪.
See here for more
So, the answer to your question is "yes and no". There's an open issue here that I have on the todo list.
I offered a temporary/potential solution for now in that issue. Basically, you would just manage the tasks in a collection yourself. Coravel gives you some lower-level methods to start/stop any jobs you want (although, it's a workaround of sorts until there is an actual feature added 😂).
You should check out builtwithdot.net/ - it's a showcase of projects built with .NET. You can filter the results by using the first filter on the top left to limit it to .NET Core.
Interesting!
We've always used Window's Task Scheduler for our CRON jobs.
This seems like an interesting alternative, and allows more control at the application level. But comparatively in our current configuration, to change the time of day or enabled/disabled status, we don't have to deploy a new version of the application to PROD, just change it in the task scheduler.
The Pro dashboard seems a lot more user friendly way of dealing with the tasks too, and wouldn't require as many user permissions.
Thanks for the tutorial
Thanks for the feedback!
One of the issues it seems many devs run into with Window's task scheduler are, as you said, basic user permissions 😂.
Plus, if you want to move all your infrastructure to serverless / container services, etc. then with something like Coravel you literally have nothing to change. Using Windows Task Scheduler def. couples you to using a full VM or bare-metal infra.
And yes, Coravel Pro stores all the schedules in your DB so you can just change schedules on PROD with no deployments 👍
.NET Core 3 will have lots of cool stuff! Looking forward to it.
Thanks for creating this beautiful solution. This is the future. Mailer, events and queue? This is really amazing!!!
Thanks!
Seams like something I can use in my next project!, nice work :)
Do you have any recommendations on how to implement this with logging with a database for .net core 3?
I think you can inject
ILogger<T>
into any class you want when using the built-in DI system.For a database, you could use something like Dapper or integrate EF core into the library (this article might help)?
Great article just what I needed! Thank you!
Thanks!
Great article! Thanks for writing it!