// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Hosting.Internal { internal class Host : IHost { private readonly ILogger _logger; private readonly IHostLifetime _hostLifetime; private readonly ApplicationLifetime _applicationLifetime; private readonly HostOptions _options; private IEnumerable _hostedServices; public Host(IServiceProvider services, IApplicationLifetime applicationLifetime, ILogger logger, IHostLifetime hostLifetime, IOptions options) { Services = services ?? throw new ArgumentNullException(nameof(services)); _applicationLifetime = (applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime))) as ApplicationLifetime; _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _hostLifetime = hostLifetime ?? throw new ArgumentNullException(nameof(hostLifetime)); _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); } public IServiceProvider Services { get; } public async Task StartAsync(CancellationToken cancellationToken = default) { _logger.Starting(); var delayStart = new TaskCompletionSource(); cancellationToken.Register(obj => ((TaskCompletionSource)obj).TrySetCanceled(), delayStart); _hostLifetime.RegisterDelayStartCallback(obj => ((TaskCompletionSource)obj).TrySetResult(null), delayStart); _hostLifetime.RegisterStopCallback(obj => (obj as IApplicationLifetime)?.StopApplication(), _applicationLifetime); await delayStart.Task; _hostedServices = Services.GetService>(); foreach (var hostedService in _hostedServices) { // Fire IHostedService.Start await hostedService.StartAsync(cancellationToken).ConfigureAwait(false); } // Fire IApplicationLifetime.Started _applicationLifetime?.NotifyStarted(); _logger.Started(); } public async Task StopAsync(CancellationToken cancellationToken = default) { _logger.Stopping(); using (var cts = new CancellationTokenSource(_options.ShutdownTimeout)) using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancellationToken)) { var token = linkedCts.Token; // Trigger IApplicationLifetime.ApplicationStopping _applicationLifetime?.StopApplication(); IList exceptions = new List(); if (_hostedServices != null) // Started? { foreach (var hostedService in _hostedServices.Reverse()) { token.ThrowIfCancellationRequested(); try { await hostedService.StopAsync(token).ConfigureAwait(false); } catch (Exception ex) { exceptions.Add(ex); } } } token.ThrowIfCancellationRequested(); await _hostLifetime.StopAsync(token); // Fire IApplicationLifetime.Stopped _applicationLifetime?.NotifyStopped(); if (exceptions.Count > 0) { var ex = new AggregateException("One or more hosted services failed to stop.", exceptions); _logger.StoppedWithException(ex); throw ex; } } _logger.Stopped(); } public void Dispose() { (Services as IDisposable)?.Dispose(); } } }