Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

Commit

Permalink
Review feedback for IApplicationLifetimeEvents
Browse files Browse the repository at this point in the history
- Renamed the type to IHostedService and added Start and Stop.
- Split up the IHostedService execution and IApplicationLifetime to avoid
circular references
- Trigger IHostedService.Start after starting the server
- Trigger IHostedService.Stop before disposing the service provider

#895 #894
  • Loading branch information
davidfowl committed Dec 6, 2016
1 parent 4abb48e commit fe9075d
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,20 @@
namespace Microsoft.AspNetCore.Hosting
{
/// <summary>
/// Allows consumers to perform cleanup during a graceful shutdown.
/// Defines methods for objects that are managed by the host.
/// </summary>
public interface IApplicationLifetimeEvents
public interface IHostedService
{
/// <summary>
/// Triggered when the application host has fully started and is about to wait
/// for a graceful shutdown.
/// Triggered when the application host has fully started and the server is waiting
/// for requests.
/// </summary>
void OnApplicationStarted();
void Start();

/// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// Requests may still be in flight. Shutdown will block until this event completes.
/// </summary>
void OnApplicationStopping();

/// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// All requests should be complete at this point. Shutdown will block
/// until this event completes.
/// </summary>
void OnApplicationStopped();

void Stop();
}
}
30 changes: 5 additions & 25 deletions src/Microsoft.AspNetCore.Hosting/Internal/ApplicationLifetime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ public class ApplicationLifetime : IApplicationLifetime
private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();
private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();
private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();
private readonly IEnumerable<IApplicationLifetimeEvents> _handlers = Enumerable.Empty<IApplicationLifetimeEvents>();
private readonly ILogger<ApplicationLifetime> _logger;

public ApplicationLifetime(ILogger<ApplicationLifetime> logger, IEnumerable<IApplicationLifetimeEvents> handlers)
public ApplicationLifetime(ILogger<ApplicationLifetime> logger)
{
_logger = logger;
_handlers = handlers;
}

/// <summary>
Expand Down Expand Up @@ -57,7 +55,7 @@ public void StopApplication()
{
try
{
ExecuteHandlers(_stoppingSource, handler => handler.OnApplicationStopping());
ExecuteHandlers(_stoppingSource);
}
catch (Exception ex)
{
Expand All @@ -75,7 +73,7 @@ public void NotifyStarted()
{
try
{
ExecuteHandlers(_startedSource, handler => handler.OnApplicationStarted());
ExecuteHandlers(_startedSource);
}
catch (Exception ex)
{
Expand All @@ -92,7 +90,7 @@ public void NotifyStopped()
{
try
{
ExecuteHandlers(_stoppedSource, handler => handler.OnApplicationStopped());
ExecuteHandlers(_stoppedSource);
}
catch (Exception ex)
{
Expand All @@ -102,7 +100,7 @@ public void NotifyStopped()
}
}

private void ExecuteHandlers(CancellationTokenSource cancel, Action<IApplicationLifetimeEvents> callback)
private void ExecuteHandlers(CancellationTokenSource cancel)
{
// Noop if this is already cancelled
if (cancel.IsCancellationRequested)
Expand All @@ -127,24 +125,6 @@ private void ExecuteHandlers(CancellationTokenSource cancel, Action<IApplication
exceptions.Add(ex);
}

// Run the handlers
foreach (var handler in _handlers)
{
try
{
callback(handler);
}
catch (Exception ex)
{
if (exceptions == null)
{
exceptions = new List<Exception>();
}

exceptions.Add(ex);
}
}

// Throw an aggregate exception if there were any exceptions
if (exceptions != null)
{
Expand Down
70 changes: 70 additions & 0 deletions src/Microsoft.AspNetCore.Hosting/Internal/HostedServiceExecutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;

namespace Microsoft.AspNetCore.Hosting.Internal
{
public class HostedServiceExecutor
{
private readonly IEnumerable<IHostedService> _services;
private readonly ILogger<HostedServiceExecutor> _logger;

public HostedServiceExecutor(ILogger<HostedServiceExecutor> logger, IEnumerable<IHostedService> services)
{
_logger = logger;
_services = services;
}

public void Start()
{
try
{
Execute(service => service.Start());
}
catch (Exception ex)
{
_logger.ApplicationError(LoggerEventIds.HostedServiceStartException, "An error occurred starting the application", ex);
}
}

public void Stop()
{
try
{
Execute(service => service.Stop());
}
catch (Exception ex)
{
_logger.ApplicationError(LoggerEventIds.HostedServiceStopException, "An error occurred stopping the application", ex);
}
}

private void Execute(Action<IHostedService> callback)
{
List<Exception> exceptions = null;

foreach (var service in _services)
{
try
{
callback(service);
}
catch (Exception ex)
{
if (exceptions == null)
{
exceptions = new List<Exception>();
}

exceptions.Add(ex);
}
}

// Throw an aggregate exception if there were any exceptions
if (exceptions != null)
{
throw new AggregateException(exceptions);
}
}
}
}
2 changes: 2 additions & 0 deletions src/Microsoft.AspNetCore.Hosting/Internal/LoggerEventIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ internal static class LoggerEventIds
public const int ApplicationStartupException = 6;
public const int ApplicationStoppingException = 7;
public const int ApplicationStoppedException = 8;
public const int HostedServiceStartException = 9;
public const int HostedServiceStopException = 10;
}
}
16 changes: 16 additions & 0 deletions src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class WebHost : IWebHost
private readonly IServiceCollection _applicationServiceCollection;
private IStartup _startup;
private ApplicationLifetime _applicationLifetime;
private HostedServiceExecutor _hostedServiceExecutor;

private readonly IServiceProvider _hostingServiceProvider;
private readonly WebHostOptions _options;
Expand Down Expand Up @@ -68,6 +69,7 @@ public WebHost(
_applicationServiceCollection = appServices;
_hostingServiceProvider = hostingServiceProvider;
_applicationServiceCollection.AddSingleton<IApplicationLifetime, ApplicationLifetime>();
_applicationServiceCollection.AddSingleton<HostedServiceExecutor>();
}

public IServiceProvider Services
Expand Down Expand Up @@ -104,11 +106,17 @@ public virtual void Start()
Initialize();

_applicationLifetime = _applicationServices.GetRequiredService<IApplicationLifetime>() as ApplicationLifetime;
_hostedServiceExecutor = _applicationServices.GetRequiredService<HostedServiceExecutor>();
var diagnosticSource = _applicationServices.GetRequiredService<DiagnosticSource>();
var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
Server.Start(new HostingApplication(_application, _logger, diagnosticSource, httpContextFactory));

// Fire IApplicationLifetime.Started
_applicationLifetime?.NotifyStarted();

// Fire IHostedService.Start
_hostedServiceExecutor.Start();

_logger.Started();
}

Expand Down Expand Up @@ -243,9 +251,17 @@ private void EnsureServer()
public void Dispose()
{
_logger?.Shutdown();

// Fire IApplicationLifetime.Stopping
_applicationLifetime?.StopApplication();

// Fire the IHostedService.Stop
_hostedServiceExecutor?.Stop();

(_hostingServiceProvider as IDisposable)?.Dispose();
(_applicationServices as IDisposable)?.Dispose();

// Fire IApplicationLifetime.Stopped
_applicationLifetime?.NotifyStopped();

HostingEventSource.Log.HostStop();
Expand Down
Loading

0 comments on commit fe9075d

Please sign in to comment.