111 lines
4.3 KiB
C#
111 lines
4.3 KiB
C#
// 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<Host> _logger;
|
|
private readonly IHostLifetime _hostLifetime;
|
|
private readonly ApplicationLifetime _applicationLifetime;
|
|
private readonly HostOptions _options;
|
|
private IEnumerable<IHostedService> _hostedServices;
|
|
|
|
public Host(IServiceProvider services, IApplicationLifetime applicationLifetime, ILogger<Host> logger,
|
|
IHostLifetime hostLifetime, IOptions<HostOptions> 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<object>();
|
|
cancellationToken.Register(obj => ((TaskCompletionSource<object>)obj).TrySetCanceled(), delayStart);
|
|
_hostLifetime.RegisterDelayStartCallback(obj => ((TaskCompletionSource<object>)obj).TrySetResult(null), delayStart);
|
|
_hostLifetime.RegisterStopCallback(obj => (obj as IApplicationLifetime)?.StopApplication(), _applicationLifetime);
|
|
|
|
await delayStart.Task;
|
|
|
|
_hostedServices = Services.GetService<IEnumerable<IHostedService>>();
|
|
|
|
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<Exception> exceptions = new List<Exception>();
|
|
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();
|
|
}
|
|
}
|
|
}
|