I am building an ASP.NET Web API (.NET 5). Other than having typical controller, I also want to have a background job running parallel all the time. For this purpose, I have created a hosted service:
public class MyHostedService : IHostedService
{
private readonly IHostApplicationLifetime _appLifetime;
private readonly ILogger _logger;
public MyHostedService(IHostApplicationLifetime appLifetime, ILogger<MyHostedService> logger)
{
_appLifetime = appLifetime ?? throw new ArgumentNullException(nameof(appLifetime));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task StartAsync(CancellationToken cancellationToken)
{
return Task.Factory.StartNew(async () =>
{
await Run(cancellationToken);
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
private async Task Run(CancellationToken cancellationToken)
{
try
{
// some long running code
}
catch (OperationCanceledException)
{
_logger.LogInformation("Application was terminated from the outside");
_appLifetime.StopApplication();
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception!");
_appLifetime.StopApplication();
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogDebug("StopAsync executes");
return Task.CompletedTask;
}
}
I registered it in ConfigureServices
:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo {Title = "My API", Version = "v1"});
});
services.AddHostedService<CacheManagerHostedService>();
}
The API works, and the MyHostedService
instance runs properly. The code in StartAsync
spins up a new thread. If I don't do that, the API server would not start listening at all.
I noticed that the app closes almost immediately when I press CTRL+C. The log in the StopAsync
is never written. I'd like to be able to run some cleanup in StopAsync
later on. What should I change?