Keeping your Web API clean and responsive often means moving heavy work out of the HTTP request pipeline.
Blocking requests while processing long-running tasks can slow down your application and hurt the user experience.
One solution is running a separate worker service, but that can quickly increase infrastructure complexity and operational costs.
A simpler alternative is using a library like Coravel, which provides background job processing, scheduling, in-memory queues and email handling directly inside your application.
Coravel
So far, we’ve already covered a couple of popular background processing solutions, including:
What makes Coravel stand out is its simplicity.
Coravel focuses on a near-zero configuration approach for task scheduling, background queues, caching, mailing and more.
It is maintained as an open-source project, while Coravel Pro adds enterprise-focused features for larger-scale applications.
Getting Started
To get started with Coravel, you need to install the NuGet package. You can do this via the NuGet Package Manager or by running the following command in the Package Manager Console:
Install-Package Coravel
Task scheduling
First, we need to register the scheduler in the service collection. We can do this by calling the AddScheduler method:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScheduler();
var app = builder.Build();
app.Run();
Now for simplest scheduling example, we can use the ScheduleAsync method to schedule a task:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScheduler();
var app = builder.Build();
app.Services.UseScheduler(scheduler =>
{
scheduler.ScheduleAsync(async () =>
{
Console.WriteLine("Coravel makes scheduling simple!");
}).EveryFiveSeconds();
});
app.Run();
And that's it! The task will run every five seconds and write the message to the console.
You can also schedule a task to run using a cron expression, daily, weekly, monthly, etc.
If you need more robust scheduling and you want to keep your Program.cs file clean, you define tasks outside of the Program.cs file using the IInvocable interface:
public class InvocableTask(ILogger<InvocableTask> logger) : IInvocable
{
public async Task Invoke()
{
await Task.Delay(1000);
logger.LogInformation("Downsides? It doesn't persist tasks in the database.");
}
}
Then you can schedule the task in the Program.cs file:
app.Services.UseScheduler(scheduler =>
{
scheduler.ScheduleAsync(async () =>
{
Console.WriteLine("Coravel makes scheduling simple!");
}).EveryFiveSeconds();
scheduler.Schedule<InvocableTask>()
.EverySeconds(10);
});
app.Run();
NOTE: This is all done in memory. If the process restarts, there is no built-in durable store like some database-backed schedulers provide. For many internal jobs that is acceptable but if persistence is important, you would need to use a different scheduler or use Coravel Pro.
Queue
Coravel’s queue is an in-memory worker that can offload work to background.
You can register the queue with the AddQueue method:
builder.Services.AddQueue();
Using dependency injection, you can inject the IQueue interface and then enqueue work:
queue.QueueAsyncTask(async() => {
await Task.Delay(1000);
Console.WriteLine("This was queued!");
});
It supports both async and sync tasks but it's also possible to queue invocable tasks:
queue.QueueInvocable<InvocableTask>();
Queuing invocables is actually the recommended way to use Coravel's queuing.
In case you have payload to pass to the task, you can use the QueueInvocableWithPayload method:
queue.QueueInvocableWithPayload<InvocableTask, Payload>(payload);
Payload is available as a implementation of the IInvocableWithPayload interface:
public class InvocableTask(ILogger<InvocableTask> logger) : IInvocable, IInvocableWithPayload<Payload>
{
public Payload Payload { get; set; }
public async Task Invoke()
{
await Task.Delay(1000);
if (Payload is { Id: var payloadId })
{
logger.LogInformation("Processing queued payload: {PayloadId}", payloadId);
return;
}
logger.LogInformation("Downsides? It doesn't persist tasks in the database.");
}
}
Mailing
Coravel also ships a mailer abstraction on top of System.Net.Mail style delivery, with Razor-based templates and optional scheduling of mail sends.
To get started, you need to install the Coravel.Mailer package:
Install-Package Coravel.Mailer
Registration follows the same philosophy as the other Coravel services. You can register the mailer with the AddMailer method:
builder.AddMailer();
Then we need to define a Mailable, which is basically a configuration for sending an email:
public class WelcomeMailable(Payload payload) : Mailable<Payload>
{
public override void Build()
{
To(payload)
.Subject("Welcome to our platform!")
.View("~/Views/Emails/Welcome.cshtml", payload);
}
}
Lastly, you can inject IMailer and send the email using the SendAsync method:
await mailer.SendAsync(new WelcomeMailable(payload));
Coravel's mailing is actually much more powerful than this. I may create a separate blog post about it in the future.
Conclusion
Coravel is a lightweight way to add scheduling, queuing and mailing to ASP.NET Core without extra infrastructure.
Its simplicity makes it a strong fit for internal jobs and fire-and-forget background work, though you trade persistence for ease of setup compared to tools like Quartz.NET or TickerQ.
If you want to check out examples I created, you can find the source code here:
Source CodeI hope you enjoyed it, subscribe and get a notification when a new blog is up!
