question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

BackgroundService StopAsync not called when stopping Web App in Azure using ASP.NET Core 6 Minimal API

See original GitHub issue

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I created the template Minimal API template with VS 2022 ASP.NET 6.0, and added a BackgroundService as a HostedService. I deployed this to Azure and it starts the Background service fine and i can see it in the logs.

However when i stop the web app in Azure, the StopAsync of the BackgroundService is not called. Do i need to hook something up in the Program.cs with the builder.Host? How in the code can i get notified that the web app is shutting down in case i need to do some other graceful shutdown? Program.cs

using MinAPI.Test.Workers;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddHostedService<Worker>();

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI();

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
       new WeatherForecast
       (
           DateTime.Now.AddDays(index),
           Random.Shared.Next(-20, 55),
           summaries[Random.Shared.Next(summaries.Length)]
       ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast");

app.Run();

internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Worker.cs

namespace MinAPI.Test.Workers
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }

            _logger.LogInformation("Worker cancellation token finished ");
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogWarning("Worker STARTING");
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogWarning("Worker STOPPING: {time}", DateTimeOffset.Now);
            return base.StopAsync(cancellationToken);
        }
    }
}

image

Expected Behavior

I would expect the line _logger.LogWarning(“Worker STOPPING: {time}”, DateTimeOffset.Now); to be hit when stopping in Azure.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

.Net 6

Anything else?

No response

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:13 (4 by maintainers)

github_iconTop GitHub Comments

4reactions
jez9999commented, Feb 26, 2023

This is a known issue for which there is a similar existing issue specific to the Worker template prior to 6.0. App Service essentially sends a different shutdown command. There is no plan to resolve this in the app service side, nor known workaround when one is running their Worker in app service. Have you tried running your worker in Azure Container Apps or in Azure Container Instances? Those options don’t have this same issue.

Out of interest why is it such a difficult fix for App Service just to send a SIGTERM? It would seem to be a one-liner.

1reaction
tdw-hughescommented, Sep 22, 2022

Hi Euan, I can tell you how we worked around this:

in startup.cs:

Register some methods here:

        public void Configure(IApplicationBuilder app, IHostApplicationLifetime applicationLifetime, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            applicationLifetime.ApplicationStopping.Register(OnShutdown);
            applicationLifetime.ApplicationStarted.Register(OnStarted);

        ... etc. ...
        }

Add this code. We created a dummy PingController to use as an endpoint. It didn’t seem to matter whether the Controller returned successful or we got an authorisation error - it worked to make ASP register properly and then the expected shutdown calls are made.

        private void OnStarted()
        {
            // Force a request on the controller, as there is a bug in ASP.NET that doesn't shutdown services gracefully at service stop until at least one request received
            Task.Factory.StartNew(() =>
            {
                try
                {
                    var client = new HttpClient();
                    client.BaseAddress = new Uri("whatever path is to this service");
                    var result = client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "api/Ping" )).Result;
                    Console.WriteLine($"Pinged an API controller to ensure shutdown will register correctly: {result.StatusCode}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            });
        }

        private void OnShutdown()
        {
            //noop - unless you have anything specific you need to do here.
        }
Read more comments on GitHub >

github_iconTop Results From Across the Web

BackgroundService StopAsync not called when stopping ...
BackgroundService StopAsync not called when stopping Web App in Azure using ASP.NET Core 6 Minimal API · c# · azure · asp.net-core ·...
Read more >
BackgroundService StopAsync not called when stopping Web ...
Coding example for the question BackgroundService StopAsync not called when stopping Web App in Azure using ASP.NET Core 6 Minimal API.
Read more >
Background tasks with hosted services in ASP.NET Core
ExecuteAsync(CancellationToken) is called to run the background service. The implementation returns a Task that represents the entire lifetime ...
Read more >
Using Background Services in ASP.NET Core
The BackgroundService class allows you to have code running in the background. In my case, I wanted to be able to queue up...
Read more >
ASP.NET Core IHostedService, BackgroundService and error ...
The interface has two methods, a StartAsync that is run on application start and StopAsync that is run on application exit. When your...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found