<p>I'm able to successfully run a .NET 5 Console Application with a <code>BackgroundService</code> in an Azure Kubernetes cluster on Ubuntu 18.04. In fact, the <code>BackgroundService</code> is all that really runs: just grabs messages from a queue, executes some actions, then terminates when Kubernetes tells it to stop, or the occasional exception.</p>
<p>It's this last scenario which is giving me problems. When the <code>BackgroundService</code> hits an unrecoverable exception, I'd like the container to stop (complete, or whatever state will cause Kubernetes to either restart or destroy/recreate the container).</p>
<p>Unfortunately, any time an exception is encountered, the <code>BackgroundService</code> <em>appears</em> to hit the <code>StopAsync()</code> function (from what I can see in the logs and console output), but the container stays in a running state and never restarts. My Main() is as appears below:</p>
<pre><code>        public static async Task Main(string[] args)
        {
            // Build service host and execute.
            var host = CreateHostBuilder(args)
                .UseConsoleLifetime()
                .Build();

            // Attach application event handlers.
            AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);

            try
            {
                Console.WriteLine(&quot;Beginning WebSec.Scanner.&quot;);
                await host.StartAsync();
                await host.WaitForShutdownAsync();
                Console.WriteLine(&quot;WebSec.Scanner has completed.&quot;);
            }
            finally
            {
                Console.WriteLine(&quot;Cleaning up...&quot;);

                // Ensure host is properly disposed.
                if (host is IAsyncDisposable ad)
                {
                    await ad.DisposeAsync();
                }
                else if (host is IDisposable d)
                {
                    d.Dispose();
                }
            }
        }
</code></pre>
<p>If relevant, those event handlers for <code>ProcessExit</code> and <code>UnhandledException</code> exist to flush the AppInsights telemetry channel (maybe that's blocking it?):</p>
<pre><code>        private static void OnProcessExit(object sender, EventArgs e)
        {
            // Ensure AppInsights logs are submitted upstream.
            Console.WriteLine(&quot;Flushing logs to AppInsights&quot;);
            TelemetryChannel.Flush();
        }

        private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var thrownException = (Exception)e.ExceptionObject;
            Console.WriteLine(&quot;Unhandled exception thrown: {0}&quot;, thrownException.Message);

            // Ensure AppInsights logs are submitted upstream.
            Console.WriteLine(&quot;Flushing logs to AppInsights&quot;);
            TelemetryChannel.Flush();
        }
</code></pre>
<p>I am only overriding <code>ExecuteAsync()</code> in the <code>BackgroundService</code>:</p>
<pre><code>        protected async override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            this.logger.LogInformation(
                &quot;Service started.&quot;);

            try
            {
                // Loop until the service is terminated.
                while (!stoppingToken.IsCancellationRequested)
                {
                    // Do some work...
                }
            }
            catch (Exception ex)
            {
                this.logger.LogWarning(
                    ex,
                    &quot;Terminating due to exception.&quot;);
            }

            this.logger.LogInformation(
                &quot;Service ending.&quot;,
        }

</code></pre>
<p>My Dockerfile is simple and has this line to run the service:</p>
<pre><code>ENTRYPOINT [&quot;dotnet&quot;, &quot;MyService.dll&quot;]
</code></pre>
<p>Am I missing something obvious? I feel like there's something about running this as a Linux container that I'm forgetting in order to make this run properly.</p>
<p>Thank you!</p>

Cory Gehr
<p>Here is a full example of how to use <code>IHostApplicationLifetime.StopApplication()</code>.</p>
<pre><code>void Main()
{
    var host = Host.CreateDefaultBuilder()
        .ConfigureServices((context, services) =&gt;
        {
            services.AddHostedService&lt;MyService&gt;();
        })
        .Build();
    
    Console.WriteLine(&quot;Starting service&quot;);

    host.Run();
    
    Console.WriteLine(&quot;Ended service&quot;);
}

// You can define other methods, fields, classes and namespaces here

public class MyService : BackgroundService
{
    private readonly IHostApplicationLifetime _lifetime;
    
    private readonly Random _rnd = new Random();
    
    public MyService(IHostApplicationLifetime lifetime)
    {
        _lifetime = lifetime;
    }
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            while (true)
            {
                stoppingToken.ThrowIfCancellationRequested();
                
                var nextNumber = _rnd.Next(10);
                if (nextNumber &lt; 8)
                {
                    Console.WriteLine($&quot;We have number {nextNumber}&quot;);
                }
                else
                {
                    throw new Exception(&quot;Number too high&quot;);
                }
                
                await Task.Delay(1000);
            }
        }
        // If the application is shutting down, ignore it
        catch (OperationCanceledException e) when (e.CancellationToken == stoppingToken)
        {
            Console.WriteLine(&quot;Application is shutting itself down&quot;);
        }
        // Otherwise, we have a real exception, so must ask the application
        // to shut itself down.
        catch (Exception e)
        {
            Console.WriteLine(&quot;Oh dear. We have an exception. Let's end the process.&quot;);
            // Signal to the OS that this was an error condition by 
            // setting the exit code.
            Environment.ExitCode = 1;
            _lifetime.StopApplication();
        }
    }
}
</code></pre>
<p>Typical output from this program will look like:</p>
<pre><code>Starting service
We have number 0
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\Users\rowla\AppData\Local\Temp\LINQPad6\_spgznchd\shadow-1
We have number 2
Oh dear. We have an exception. Let's end the process.
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
Ended service
</code></pre>
