In this post, we will learn to setup a scheduled repeating task with .NET Core framework. We will schedule a task that will repeatedly run at our desired time.
Introduction
In a client-server application, a scheduled task or service is a common need. Maybe you need to move your log files to a separate bucket on a daily basis. Or you want to clean up data in your database every weekend.
A scheduled service can be run at your desired time which enables you to move certain tasks when there are least users in your system, reducing impact and load on the server.
How To Create A Repeating Task In .NET Core
There are many ways to create a repeating scheduled task with .NET core framework. In this post, we will learn to create such scheduler in the following steps:
- Create a background task with the help of
IHostedService
. - Use a
Timer
to setup a repeating task. - Implement a delayed
Task
to setup a schedule to run task at desired time.
Setup
Let’s say we are looking to create a service that removes inactive users from our system. In order to reduce server impact, we want to run schedule this service at 1 am every night.
Implementing IHostedervice
To create such service, we will first create a class that implements the IHostedervice
interface which exposes following two methods:
- StartAsync: Triggered when the application host is ready to start the service.
public System.Threading.Tasks.Task StartAsync (System.Threading.CancellationToken cancellationToken);
- StopAsync: Triggered when the application host is performing a graceful shutdown.
public System.Threading.Tasks.Task StopAsync (System.Threading.CancellationToken cancellationToken);
Implementing these two methods, we create our class in this way:
public class AccountRemovalService : IHostedService
{
private readonly IAccountService accountServive;
public AccountRemovalService(IAccountService accountServive)
{
this.accountServive = accountServive;
}
public Task StartAsync(CancellationToken cancellationToken)
{
// todo:
}
public Task StopAsync(CancellationToken cancellationToken)
{
// todo:
}
private void RemoveInactiveAccounts(object state)
{
accountServive.DeleteInactiveUserData();
}
}
Here, AccountRemovalService
class is implementing the IHostedService
interface. The IAccountService
is the service that you will have created implementing the actual business logic for removing accounts.
Add Timer To Repeat Task
Next, we add a Timer
which will repeatedly call the RemoveInactiveAccounts
method.
The timer will be initialized in the StartAsync
method and can be removed if required from StopAsync
method.
public Task StartAsync(CancellationToken cancellationToken)
{
// timer repeates call to RemoveScheduledAccounts every 24 hours.
_timer = new Timer(
RemoveInactiveAccounts,
null,
TimeSpan.Zero,
TimeSpan.FromHours(24)
);
return Task.CompletedTask;
}
/// Call the Stop async method if required from within the app.
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
In this case, our Timer
repeats the call to RemoveInactiveAccounts
every 24 hours.
Registering The Hosted Service
To configure the above created service, we need to register with the AddHostedService
method in the startup.
services.AddHostedService<AccountRemovalService>();
Now, when you run your program with dotnet run
, the hosted service kicks in and it places the AccountRemovalService
in motion with the Timer
.
Scheduling Timer To Repeat At Desired Time
Right now, although we have setup a repeating task which occurs on a daily basis, there’s a small issue we still have here.
We wanted to run this code at 1 am every night, but right now, it is not scheduled to run exactly at our desired time. In fact, the task runs right after the start of initial program or deployment to the server and repeats after every 24 hours.
So, if we had started the .NET app at 2 pm, our service will have repeated everyday at 2 pm.
So, how to schedule this task to run exactly at 1 am?
Delay Timer Initialization
We will design our solution in the following two steps:
- Calculate the time difference between the next run time and current time period.
- Delay the timer initialization until the next run time.
For, calculating the next run time, we can make use of DateTime.Today
which returns a date time object with today’s date and time as midnight value.
Then, we will use a delayed Task
.
So, our implementation will now look like this:
public Task StartAsync(CancellationToken cancellationToken)
{
TimeSpan interval = TimeSpan.FromHours(24);
//calculate time to run the first time & delay to set the timer
//DateTime.Today gives time of midnight 00.00
var nextRunTime = DateTime.Today.AddDays(1).AddHours(1);
var curTime = DateTime.Now;
var firstInterval = nextRunTime.Subtract(curTime);
Action action = () =>
{
var t1 = Task.Delay(firstInterval);
t1.Wait();
//remove inactive accounts at expected time
RemoveScheduledAccounts(null);
//now schedule it to be called every 24 hours for future
// timer repeates call to RemoveScheduledAccounts every 24 hours.
_timer = new Timer(
RemoveScheduledAccounts,
null,
TimeSpan.Zero,
interval
);
};
// no need to await this call here because this task is scheduled to run much much later.
Task.Run(action);
return Task.CompletedTask;
}
Wrapping Up
In this post, we looked at how we can create a scheduled service in a .NET core environment. We initially created a service that can be configured to run after a certain interval. Then we configured it to run at a specific time every day.
You can use the same logic to create scheduled services with .NET as per your need. Good luck.
Checkout our other articles on .NET Core here.