How to set ShutdownTimeout using HostBuilder Generic Host ref StopAsync OperationCanceledException
Asked Answered
V

1

6

Looking into the source code, the default Timeout for StopAsync is 5 seconds. WebHostBuilder provides an extension method UseShutdownTimeout for easy setting. But no such equivalent exists for HostBuilder.

I know I'm probably abusing the intent of HostBuilder by wanting more than 5 second timeout, but it's a nice framework for managing a collection of interdependent jobs.

I'd really appreciate some guidance on how to do with HostBuilder what UseShutdownTimeout does for WebHostBuilder whilst still working with official NuGet packages. I had a look at maybe extending HostingAbstractionsHostBuilderExtensions but it's a static class...

Sample console app below for triggering the StopAsync OperationCanceledException event. Simply Ctrl+C before 10 seconds are up.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace StackOverflow_GenericHost_StopAsync
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var host = new HostBuilder()                
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddSingleton<IHostedService, MustRunToCompletionService>();
                })

                .Build();


            await host.StartAsync();

            try
            {
                await host.WaitForShutdownAsync();
            }
            catch (OperationCanceledException ex)
            {
                // We have completed a controlled shutdown but the Exception is ugly
                Console.WriteLine(ex);
                Console.ReadKey();
            }

            // just hangs if we don't
            host.Dispose();

        }
    }

    class MustRunToCompletionService : IHostedService 
    {
        private Task _longRunningTask;

        private async Task MustCompleteProcess()
        {
            // simulate long running job
            Thread.Sleep(15000);
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _longRunningTask = Task.Run(MustCompleteProcess);
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            // ignore cancellationToken, I really need this to run to completion
            return Task.WhenAll(_longRunningTask);
        }

    }

}
Vivia answered 20/10, 2018 at 22:46 Comment(1)
Wrap HostBuilder instance with a using on creation or before first usage in your case the host.StartAsync() call. If that where to throw for instance your call to dispose at the bottom would not be reached.Carmarthenshire
V
9

I gleaned the answer thanks to this post about SuppressStatusMessages

.ConfigureServices((hostContext, services) =>
    {
    services.Configure<HostOptions>(o => o.ShutdownTimeout = TimeSpan.FromSeconds(90));
Vivia answered 21/10, 2018 at 15:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.