1

Lets have this WorkerSample application:

Program.cs

using WorkerSample;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
    })
    .Build();

host.Run();
Console.WriteLine("Program terminated");

Worker.cs:

namespace WorkerSample;

public class Worker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        Console.WriteLine("Worker executing ...");
        try
        {
            await Task.Delay(Timeout.Infinite, stoppingToken);
        }
        catch (OperationCanceledException) { }

        try
        {
            await Task.Delay(25000);
            Console.WriteLine("I have shut down gracefully");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error shutting down gracefully \n {ex.ToString()}");
        }
        finally
        {
            Console.WriteLine("Finally block called");
        }
    }
}

If I run this app on .NET 6.0 and press Ctrl+C:

with await Task.Delay(5000) I see the following output:

Worker executing ...
I have shut down gracefully
Finally block called
Program terminated

So I have at least 5 seconds for shutting down gracefully.

With await Task.Delay(6000) I see the following output:

Worker executing ...
Program terminated

So I have less than 6 seconds for shutting down gracefully

In .NET 7.0 things changed. I have al least 25 seconds and less than 30 seconds for shutting down gracefully.

How much time do I have for shutting down gracefully? Does it depend only .NET version? Is it configurable?

Jesús López
  • 8,338
  • 7
  • 40
  • 66
  • Where are you getting the phrase "shooting down" from? Are you trying to stop a service? There are certainly graceful ways to do that. The amount of time it takes to stop a service depends on a number of factors; it depends on what the service is doing when you try to stop it, how long it takes to "spin down" dependent services, etc. – Robert Harvey Mar 26 '23 at 20:34
  • @Robert Harvey If you create a .NET worker application. `dotnet new worker` execute it, and press Ctrl+C you see the following on the console `info: Microsoft.Hosting.Lifetime[0] Application is shutting down...` – Jesús López Mar 26 '23 at 20:39
  • You can set the default timeout for stopping with https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.hostoptions.shutdowntimeout – Vadim Martynov Mar 26 '23 at 20:39
  • "Shutting down," not "Shooting down." – Robert Harvey Mar 26 '23 at 20:43
  • @VadimMartynov could you make your comment an answer?. Just ad a call to .ConfigureHostOptions to IHostBuilder – Jesús López Mar 26 '23 at 20:51

1 Answers1

2

HostOptions.ShutdownTimeout stores the default timeout for IHost.StopAsync method. Default timeout is 5 seconds for .NET Core and .NET 5 and 30 seconds for .NET 6 and .NET 7.

StopAsync is called when the application receives the shut down (SIGTERM) signal, for example when you push CTRL+C in the console window, or the app is stopped by the host system. This allows you to close any open connections, dispose resources, and generally clean up your class as required.

HostOptions isn't explicitly configured anywhere by default, so you will need to configure it manually. For example, the following config increases the timeout to 15s:

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
        services.Configure<HostOptions>(
                opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(15));
    })
    .Build();

Alternatively, you can also load the timeout from configuration. For example, if you add the following to appsettings.json:

{
    "HostOptions": {
        "ShutdownTimeout": "00:00:15"
    }
    // other config
}

You can then bind the HostOptions configuration section to the HostOptions object:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHostedService<Worker>();
builder.Services.Configure<HostOptions>(
    builder.Configuration.GetSection("HostOptions"));
Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43
  • What about this: `IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddHostedService(); }) .ConfigureHostOptions(options => { options.ShutdownTimeout = TimeSpan.FromSeconds(30); }) .Build();` – Jesús López Mar 26 '23 at 20:54