-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Watch for parent process exit (#333)
* Add dependent process watcher service Adds an IHostedService that will watch one or more dependent processes and call IHostApplicationLifetime.StopApplication when a dependent process exits * Use dependent process watcher in example hosts and template Registers the dependent process watcher hosted service if the `AppStoreConnect:Adapter:Host:ParentPid` configuration setting value is greater than zero.
- Loading branch information
1 parent
5ad2b0c
commit 894bf94
Showing
6 changed files
with
186 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
src/DataCore.Adapter.AspNetCore.Common/Internal/DependentProcessWatcher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace DataCore.Adapter.AspNetCore.Internal { | ||
|
||
/// <summary> | ||
/// <see cref="IHostedService"/> that watches a set of dependent processes and will request | ||
/// that the application gracefully exits if any of the dependent processes exit. | ||
/// </summary> | ||
internal sealed partial class DependentProcessWatcher : BackgroundService { | ||
|
||
/// <summary> | ||
/// The <see cref="IHostApplicationLifetime"/> that is used to request graceful shutdown | ||
/// if required. | ||
/// </summary> | ||
private readonly IHostApplicationLifetime _hostApplicationLifetime; | ||
|
||
/// <summary> | ||
/// Logging. | ||
/// </summary> | ||
private readonly ILogger<DependentProcessWatcher> _logger; | ||
|
||
/// <summary> | ||
/// The process IDs to watch. | ||
/// </summary> | ||
private readonly int[] _pids; | ||
|
||
|
||
/// <summary> | ||
/// Creates a new <see cref="DependentProcessWatcher"/> instance. | ||
/// </summary> | ||
/// <param name="pids"> | ||
/// The process IDs to watch. Note that specifying a PID that does not exist will result | ||
/// in immediate shutdown of the host application when <see cref="ExecuteAsync"/> is called. | ||
/// </param> | ||
/// <param name="hostApplicationLifetime"> | ||
/// The <see cref="IHostApplicationLifetime"/>. | ||
/// </param> | ||
/// <param name="logger"> | ||
/// The <see cref="ILogger"/>. | ||
/// </param> | ||
/// <exception cref="ArgumentNullException"> | ||
/// <paramref name="pids"/> is <see langword="null"/>. | ||
/// </exception> | ||
/// <remarks> | ||
/// Specifying a PID that does not exist will result in immediate shutdown of the host | ||
/// application when <see cref="ExecuteAsync"/> is called. | ||
/// </remarks> | ||
public DependentProcessWatcher(IEnumerable<int> pids, IHostApplicationLifetime hostApplicationLifetime, ILogger<DependentProcessWatcher> logger) { | ||
_logger = logger; | ||
_hostApplicationLifetime = hostApplicationLifetime; | ||
_pids = pids?.ToArray() ?? throw new ArgumentNullException(nameof(pids)); | ||
} | ||
|
||
|
||
/// <inheritdoc/> | ||
protected override Task ExecuteAsync(CancellationToken stoppingToken) { | ||
foreach (var pid in _pids) { | ||
var process = Process.GetProcessById(pid); | ||
if (process == null) { | ||
LogProcessNotFound(pid); | ||
_hostApplicationLifetime.StopApplication(); | ||
break; | ||
} | ||
|
||
var name = process.ProcessName; | ||
|
||
LogWatchingProcess(pid, name); | ||
|
||
process.EnableRaisingEvents = true; | ||
process.Exited += (sender, args) => { | ||
if (!stoppingToken.IsCancellationRequested) { | ||
LogProcessExited(pid, name); | ||
_hostApplicationLifetime.StopApplication(); | ||
} | ||
}; | ||
} | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
|
||
[LoggerMessage(0, LogLevel.Information, "Watching dependent process '{name}' (PID: {pid}).")] | ||
partial void LogWatchingProcess(int pid, string name); | ||
|
||
[LoggerMessage(1, LogLevel.Warning, "Dependent process '{name}' (PID: {pid}) has exited.")] | ||
partial void LogProcessExited(int pid, string name); | ||
|
||
[LoggerMessage(2, LogLevel.Warning, "Dependent process {pid} does not exist or has already exited.")] | ||
partial void LogProcessNotFound(int pid); | ||
|
||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
src/DataCore.Adapter.AspNetCore.Common/PublicAPI.Unshipped.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
#nullable enable | ||
static Microsoft.Extensions.DependencyInjection.CommonAdapterConfigurationExtensions.AddDependentProcessWatcher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, int pid, params int[]! additionalPids) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! | ||
static Microsoft.Extensions.DependencyInjection.CommonAdapterConfigurationExtensions.AddDependentProcessWatcher(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Collections.Generic.IEnumerable<int>! pids) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! | ||
static Microsoft.Extensions.DependencyInjection.CommonAdapterConfigurationExtensions.AddHostInfo(this DataCore.Adapter.DependencyInjection.IAdapterConfigurationBuilder! builder, System.Action<DataCore.Adapter.Common.HostInfoBuilder!>! configure) -> DataCore.Adapter.DependencyInjection.IAdapterConfigurationBuilder! | ||
static Microsoft.Extensions.DependencyInjection.CommonAdapterConfigurationExtensions.AddHostInfo(this DataCore.Adapter.DependencyInjection.IAdapterConfigurationBuilder! builder, System.Action<System.IServiceProvider!, DataCore.Adapter.Common.HostInfoBuilder!>! configure) -> DataCore.Adapter.DependencyInjection.IAdapterConfigurationBuilder! | ||
static Microsoft.Extensions.DependencyInjection.CommonAdapterConfigurationExtensions.WithInstanceId(this DataCore.Adapter.Common.HostInfoBuilder! builder, string! instanceId) -> DataCore.Adapter.Common.HostInfoBuilder! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters