Skip to content

Commit c894584

Browse files
authored
[Spa] Try additional hooks to kill the application (#34427)
* [Spa] Brings back the old application stopping hook for redundancy. * Uses powershell script to monitor the .NET process on windows from outside and kills all the SPA processes when it detects the .net process has been killed.
1 parent 66ceea4 commit c894584

File tree

1 file changed

+47
-9
lines changed

1 file changed

+47
-9
lines changed

src/Middleware/Spa/SpaProxy/src/SpaProxyLaunchManager.cs

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using Microsoft.Extensions.Logging;
5-
using Microsoft.Extensions.Options;
6-
using System;
74
using System.Diagnostics;
8-
using System.IO;
95
using System.Net.Http;
106
using System.Net.Http.Headers;
11-
using System.Threading;
12-
using System.Threading.Tasks;
7+
using Microsoft.Extensions.Hosting;
8+
using Microsoft.Extensions.Logging;
9+
using Microsoft.Extensions.Options;
1310

1411
namespace Microsoft.AspNetCore.SpaProxy
1512
{
@@ -25,16 +22,16 @@ internal class SpaProxyLaunchManager : IDisposable
2522

2623
public SpaProxyLaunchManager(
2724
ILogger<SpaProxyLaunchManager> logger,
25+
IHostApplicationLifetime appLifetime,
2826
IOptions<SpaDevelopmentServerOptions> options)
2927
{
3028
_options = options.Value;
3129
_logger = logger;
30+
appLifetime.ApplicationStopping.Register(() => Dispose(true));
3231
}
3332

3433
public void StartInBackground(CancellationToken cancellationToken)
3534
{
36-
_logger.LogInformation($"No SPA development server running at {_options.ServerUrl} found.");
37-
3835
// We are not waiting for the SPA proxy to launch, instead we are going to rely on a piece of
3936
// middleware to display an HTML document while the SPA proxy is not ready, refresh every three
4037
// seconds and redirect to the SPA proxy url once it is ready.
@@ -45,6 +42,7 @@ public void StartInBackground(CancellationToken cancellationToken)
4542
{
4643
if (_launchTask == null)
4744
{
45+
_logger.LogInformation($"No SPA development server running at {_options.ServerUrl} found.");
4846
_launchTask = UpdateStatus(StartSpaProcessAndProbeForLiveness(cancellationToken));
4947
}
5048
}
@@ -190,6 +188,46 @@ private void LaunchDevelopmentProxy()
190188
WorkingDirectory = Path.Combine(AppContext.BaseDirectory, _options.WorkingDirectory)
191189
};
192190
_spaProcess = Process.Start(info);
191+
if (OperatingSystem.IsWindows() && _spaProcess != null)
192+
{
193+
var stopScript = $@"do{{
194+
try
195+
{{
196+
$processId = Get-Process -PID {Environment.ProcessId} -ErrorAction Stop;
197+
}}catch
198+
{{
199+
$processId = $null;
200+
}}
201+
Start-Sleep -Seconds 1;
202+
}}while($processId -ne $null);
203+
204+
try
205+
{{
206+
taskkill /T /F /PID {_spaProcess.Id};
207+
}}
208+
catch
209+
{{
210+
}}";
211+
var stopScriptInfo = new ProcessStartInfo(
212+
"powershell.exe",
213+
string.Join(" ", "-NoProfile", "-C", stopScript))
214+
{
215+
CreateNoWindow = true,
216+
WorkingDirectory = Path.Combine(AppContext.BaseDirectory, _options.WorkingDirectory)
217+
};
218+
219+
var stopProcess = Process.Start(stopScriptInfo);
220+
if (stopProcess == null || stopProcess.HasExited)
221+
{
222+
_logger.LogWarning($"SPA process shutdown script '{stopProcess?.Id}' failed to start. The SPA proxy might" +
223+
$" remain open if the dotnet process is terminated abruptly. Use the operating system command to kill" +
224+
$"the process tree for {_spaProcess.Id}");
225+
}
226+
else
227+
{
228+
_logger.LogDebug($"Watch process '{stopProcess}' started.");
229+
}
230+
}
193231
}
194232
catch (Exception exception)
195233
{
@@ -199,7 +237,7 @@ private void LaunchDevelopmentProxy()
199237

200238
public Task StopAsync(CancellationToken cancellationToken)
201239
{
202-
// We don't need to do anything here since Dispose will take care of cleaning up the process if necessary.
240+
Dispose(true);
203241
return Task.CompletedTask;
204242
}
205243

0 commit comments

Comments
 (0)