Add more logging to iis graceful shutdown (#7068)

This commit is contained in:
Pavel Krymets 2019-01-28 16:23:55 -08:00 committed by GitHub
parent 81d0a9e467
commit 963508b9b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 71 additions and 28 deletions

View File

@ -453,49 +453,91 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
internal static extern bool EnumWindows(EnumWindowProc callback, IntPtr lParam); internal static extern bool EnumWindows(EnumWindowProc callback, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName,int nMaxCount); internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName,int nMaxCount);
[DllImport("kernel32.dll")]
internal static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
} }
private void SendStopMessageToProcess(int pid) private void SendStopMessageToProcess(int pid)
{ {
Logger.LogInformation($"Sending shutdown request to {pid}");
var found = false; var found = false;
WindowsNativeMethods.EnumWindows((ptr, param) => { var extraLogging = false;
WindowsNativeMethods.GetWindowThreadProcessId(ptr, out var windowProcessId); var retryCount = 5;
if (pid == windowProcessId)
while (!found && retryCount > 0)
{
Logger.LogInformation($"Sending shutdown request to {pid}");
WindowsNativeMethods.EnumWindows((ptr, param) => {
WindowsNativeMethods.GetWindowThreadProcessId(ptr, out var windowProcessId);
if (extraLogging)
{
Logger.LogDebug($"EnumWindow returned {ptr} belonging to {windowProcessId}");
}
if (pid == windowProcessId)
{
// 256 is the max length
var className = new StringBuilder(256);
if (WindowsNativeMethods.GetClassName(ptr, className, className.Capacity) == 0)
{
throw new InvalidOperationException($"Unable to get window class name: {Marshal.GetLastWin32Error()}");
}
if (!string.Equals(className.ToString(), "IISEXPRESS", StringComparison.OrdinalIgnoreCase))
{
Logger.LogDebug($"Skipping window {ptr} with class name {className}");
// skip windows without IISEXPRESS class
return true;
}
var hWnd = new HandleRef(null, ptr);
if (!WindowsNativeMethods.PostMessage(hWnd, 0x12, IntPtr.Zero, IntPtr.Zero))
{
throw new InvalidOperationException($"Unable to PostMessage to process {pid}. LastError: {Marshal.GetLastWin32Error()}");
}
found = true;
return false;
}
return true;
}, IntPtr.Zero);
if (!found)
{ {
// 256 is the max length Thread.Sleep(100);
var className = new StringBuilder(256);
if (WindowsNativeMethods.GetClassName(ptr, className, className.Capacity) == 0)
{
throw new InvalidOperationException($"Unable to get window class name: {Marshal.GetLastWin32Error()}");
}
if (!string.Equals(className.ToString(), "IISEXPRESS", StringComparison.OrdinalIgnoreCase))
{
// skip windows without IISEXPRESS class
return true;
}
var hWnd = new HandleRef(null, ptr);
if (!WindowsNativeMethods.PostMessage(hWnd, 0x12, IntPtr.Zero, IntPtr.Zero))
{
throw new InvalidOperationException($"Unable to PostMessage to process {pid}. LastError: {Marshal.GetLastWin32Error()}");
}
found = true;
return false;
} }
return true; // Add extra logging if first try was unsuccessful
}, IntPtr.Zero); extraLogging = true;
retryCount--;
}
if (!found) if (!found)
{ {
TriggerCrash(pid);
throw new InvalidOperationException($"Unable to find main window for process {pid}"); throw new InvalidOperationException($"Unable to find main window for process {pid}");
} }
} }
private void TriggerCrash(int pid)
{
try
{
Logger.LogInformation($"Trying to crash the process {pid}");
var process = Process.GetProcessById(pid);
// Calling CreateRemoteThread as 0x1 as thread function pointer should cause a crash
WindowsNativeMethods.CreateRemoteThread(process.Handle, IntPtr.Zero, 0, (IntPtr)1, IntPtr.Zero, 0, IntPtr.Zero);
}
catch (Exception e)
{
Logger.LogInformation(e, "Exception while trying to crash the process");
}
}
private void GracefullyShutdownProcess(Process hostProcess) private void GracefullyShutdownProcess(Process hostProcess)
{ {
if (hostProcess != null && !hostProcess.HasExited) if (hostProcess != null && !hostProcess.HasExited)
@ -514,6 +556,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
if (hostProcess.ExitCode != 0) if (hostProcess.ExitCode != 0)
{ {
Logger.LogWarning($"IISExpress exit code is non-zero after graceful shutdown. Exit code: {hostProcess.ExitCode}"); Logger.LogWarning($"IISExpress exit code is non-zero after graceful shutdown. Exit code: {hostProcess.ExitCode}");
throw new InvalidOperationException($"IISExpress exit code is non-zero after graceful shutdown. Exit code: {hostProcess.ExitCode}.");
} }
} }
else else