DotNetT2 Dark_1200x303

Let’s explore how to leverage the Worker Service template available with .NET Core to set up and run long-running processes across different environments.

.NET Core’s Worker Service provides a newer template for some common code around services with the added benefit of being cross-platform.

Worker Service should not be confused with Service Worker. Service Worker is a pseudo background thread that pulls resources as your webpage loads and can cache. The former is a server-side executable that has no UI and can run continuously or on timed intervals.

While creating long-running background processes has long been part of programming, this newer template allows simple creation and running of the service across many different OSes.

Getting Started

With .NET Core, we can build our project with a focus on the business concerns, but the target runtime environment takes a backseat to the features.

Getting our initial project built out is a breeze with Worker Service Template. To get started, we can create our initial solution with the following command:

dotnet new worker -o BackgroundWorkerExample

After creating the project, you’ll notice that there are only two main files: Program.cs and Worker.cs. Program.cs is the main runner of the worker. All of the logic for setting up the worker is performed in the Program.cs file.

The Worker.cs is where our business logic is going to live. You can set it up to run continuously or add in delays to the runner. Inside of the ExecuteAsync is the entrance to the worker code.

Writing Your Code

The new template for creating Worker Services makes it easy to build a cross-platform worker that can be run anywhere. Due to the template and libraries, we can focus on the business logic before having to worry about the environment that it would run in.

Windows Service

In order to adopt this service for Windows, you will need to download the WindowsService NuGet package.

Microsoft.Extensions.Hosting.WindowsServices

After you have downloaded the package, you’ll need to go inside the Program.cs file and add a single line of code:

...
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseWindowsService() //←--------- This Line
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker>();
            });
...

Linux Systemd

In order to adopt this service for Linux, you’ll need to download the Systemd NuGet package.

Microsoft.Extensions.Hosting.Systemd

After you have downloaded the package, you’ll need to go inside the Program.cs file and add a single line of code:

...
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseSystemd()   //←--------- This Line
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker>();
            });
...

Not Sure Yet

Both the UseWindowsService() and UseSystemd() are context-aware and they can be applied at the same time and will only be used when the context is appropriate. You can make your Worker Service compatibility to be run in either a Windows or Linux environment without having a second codebase.

Continuous or Intervals?

At this point, we have talked about creating the project and acclimating it to different environments where it can be run. The next step would be deciding on how it is going to do its work. By default, the worker service will run continuously.

With a small adjustment, we can change the default behavior from a continuous worker to a worker that runs on an interval.

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        ...
        await Task.Delay(1000, stoppingToken);
    }
}

By making this change, we can have the worker operate on a programmatic delay that responds to cancellations. Also, we can add dynamic intervals for retries and other logic without having to manually change the worker itself.

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        int delay = 1000; 
        try {
            ...
        } 
        catch(Exception) {
            delay = delay * 2;
        } 
        await Task.Delay(delay, stoppingToken);
    }
}

We’ve gone through the basics of getting started with .NET Core’s Worker Service along with how to adapt it for many different runtime environments along with a few tweaks to make the worker work better for you. This another tool that .NET Core makes available to make it a great choice to solve your Worker Service needs. Happy Coding!

For the source code, check out the GitHub Repo.


Richard Reedy
About the Author

Richard Reedy

Richard Reedy has been working in the software field for over 12 years. He has worked on everything from operations to backend server development to really awesome frontend UI. He enjoys building great products and the teams around them. His latest venture is enabling technology to better serve food trucks around the United States.

Related Posts

Comments

Comments are disabled in preview mode.