[3.1.x] Fix dotnet.exe process recovery after abnormal exit in… (#17103)
This commit is contained in:
parent
6902b14471
commit
9fded4c4aa
|
|
@ -14,6 +14,7 @@ class ConfigUtility
|
||||||
#define CS_ASPNETCORE_HANDLER_SETTINGS L"handlerSettings"
|
#define CS_ASPNETCORE_HANDLER_SETTINGS L"handlerSettings"
|
||||||
#define CS_ASPNETCORE_HANDLER_VERSION L"handlerVersion"
|
#define CS_ASPNETCORE_HANDLER_VERSION L"handlerVersion"
|
||||||
#define CS_ASPNETCORE_DEBUG_FILE L"debugFile"
|
#define CS_ASPNETCORE_DEBUG_FILE L"debugFile"
|
||||||
|
#define CS_ASPNETCORE_ENABLE_OUT_OF_PROCESS_CONSOLE_REDIRECTION L"enableOutOfProcessConsoleRedirection"
|
||||||
#define CS_ASPNETCORE_DEBUG_LEVEL L"debugLevel"
|
#define CS_ASPNETCORE_DEBUG_LEVEL L"debugLevel"
|
||||||
#define CS_ASPNETCORE_HANDLER_SETTINGS_NAME L"name"
|
#define CS_ASPNETCORE_HANDLER_SETTINGS_NAME L"name"
|
||||||
#define CS_ASPNETCORE_HANDLER_SETTINGS_VALUE L"value"
|
#define CS_ASPNETCORE_HANDLER_SETTINGS_VALUE L"value"
|
||||||
|
|
@ -40,6 +41,13 @@ public:
|
||||||
return FindKeyValuePair(pElement, CS_ASPNETCORE_DEBUG_LEVEL, strDebugFile);
|
return FindKeyValuePair(pElement, CS_ASPNETCORE_DEBUG_LEVEL, strDebugFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
HRESULT
|
||||||
|
FindEnableOutOfProcessConsoleRedirection(IAppHostElement* pElement, STRU& strEnableOutOfProcessConsoleRedirection)
|
||||||
|
{
|
||||||
|
return FindKeyValuePair(pElement, CS_ASPNETCORE_ENABLE_OUT_OF_PROCESS_CONSOLE_REDIRECTION, strEnableOutOfProcessConsoleRedirection);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static
|
static
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,7 @@ PROCESS_MANAGER::GetProcess(
|
||||||
pConfig->QueryAnonymousAuthEnabled(),
|
pConfig->QueryAnonymousAuthEnabled(),
|
||||||
pConfig->QueryEnvironmentVariables(),
|
pConfig->QueryEnvironmentVariables(),
|
||||||
pConfig->QueryStdoutLogEnabled(),
|
pConfig->QueryStdoutLogEnabled(),
|
||||||
|
pConfig->QueryEnableOutOfProcessConsoleRedirection(),
|
||||||
fWebsocketSupported,
|
fWebsocketSupported,
|
||||||
pConfig->QueryStdoutLogFile(),
|
pConfig->QueryStdoutLogFile(),
|
||||||
pConfig->QueryApplicationPhysicalPath(), // physical path
|
pConfig->QueryApplicationPhysicalPath(), // physical path
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ SERVER_PROCESS::Initialize(
|
||||||
BOOL fAnonymousAuthEnabled,
|
BOOL fAnonymousAuthEnabled,
|
||||||
std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
|
std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
|
||||||
BOOL fStdoutLogEnabled,
|
BOOL fStdoutLogEnabled,
|
||||||
|
BOOL fEnableOutOfProcessConsoleRedirection,
|
||||||
BOOL fWebSocketSupported,
|
BOOL fWebSocketSupported,
|
||||||
STRU *pstruStdoutLogFile,
|
STRU *pstruStdoutLogFile,
|
||||||
STRU *pszAppPhysicalPath,
|
STRU *pszAppPhysicalPath,
|
||||||
|
|
@ -43,6 +44,7 @@ SERVER_PROCESS::Initialize(
|
||||||
m_fWindowsAuthEnabled = fWindowsAuthEnabled;
|
m_fWindowsAuthEnabled = fWindowsAuthEnabled;
|
||||||
m_fBasicAuthEnabled = fBasicAuthEnabled;
|
m_fBasicAuthEnabled = fBasicAuthEnabled;
|
||||||
m_fAnonymousAuthEnabled = fAnonymousAuthEnabled;
|
m_fAnonymousAuthEnabled = fAnonymousAuthEnabled;
|
||||||
|
m_fEnableOutOfProcessConsoleRedirection = fEnableOutOfProcessConsoleRedirection;
|
||||||
m_pProcessManager->ReferenceProcessManager();
|
m_pProcessManager->ReferenceProcessManager();
|
||||||
m_fDebuggerAttached = FALSE;
|
m_fDebuggerAttached = FALSE;
|
||||||
|
|
||||||
|
|
@ -1030,6 +1032,15 @@ SERVER_PROCESS::SetupStdHandles(
|
||||||
saAttr.bInheritHandle = TRUE;
|
saAttr.bInheritHandle = TRUE;
|
||||||
saAttr.lpSecurityDescriptor = NULL;
|
saAttr.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
|
if (!m_fEnableOutOfProcessConsoleRedirection)
|
||||||
|
{
|
||||||
|
pStartupInfo->dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
pStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
|
||||||
|
pStartupInfo->hStdError = INVALID_HANDLE_VALUE;
|
||||||
|
pStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_fStdoutLogEnabled)
|
if (!m_fStdoutLogEnabled)
|
||||||
{
|
{
|
||||||
CreatePipe(&m_hStdoutHandle, &m_hStdErrWritePipe, &saAttr, 0 /*nSize*/);
|
CreatePipe(&m_hStdoutHandle, &m_hStdErrWritePipe, &saAttr, 0 /*nSize*/);
|
||||||
|
|
@ -1770,6 +1781,8 @@ SERVER_PROCESS::SERVER_PROCESS() :
|
||||||
m_dwListeningProcessId(0),
|
m_dwListeningProcessId(0),
|
||||||
m_hListeningProcessHandle(NULL),
|
m_hListeningProcessHandle(NULL),
|
||||||
m_hShutdownHandle(NULL),
|
m_hShutdownHandle(NULL),
|
||||||
|
m_hStdErrWritePipe(NULL),
|
||||||
|
m_hReadThread(nullptr),
|
||||||
m_randomGenerator(std::random_device()())
|
m_randomGenerator(std::random_device()())
|
||||||
{
|
{
|
||||||
//InterlockedIncrement(&g_dwActiveServerProcesses);
|
//InterlockedIncrement(&g_dwActiveServerProcesses);
|
||||||
|
|
@ -1866,13 +1879,15 @@ SERVER_PROCESS::~SERVER_PROCESS()
|
||||||
m_pProcessManager = NULL;
|
m_pProcessManager = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_hStdoutHandle != NULL)
|
if (m_hStdErrWritePipe != NULL)
|
||||||
{
|
{
|
||||||
if (m_hStdoutHandle != INVALID_HANDLE_VALUE)
|
if (m_hStdErrWritePipe != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
CloseHandle(m_hStdoutHandle);
|
FlushFileBuffers(m_hStdErrWritePipe);
|
||||||
|
CloseHandle(m_hStdErrWritePipe);
|
||||||
}
|
}
|
||||||
m_hStdoutHandle = NULL;
|
|
||||||
|
m_hStdErrWritePipe = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forces ReadFile to cancel, causing the read loop to complete.
|
// Forces ReadFile to cancel, causing the read loop to complete.
|
||||||
|
|
@ -1907,6 +1922,15 @@ SERVER_PROCESS::~SERVER_PROCESS()
|
||||||
m_hReadThread = nullptr;
|
m_hReadThread = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_hStdoutHandle != NULL)
|
||||||
|
{
|
||||||
|
if (m_hStdoutHandle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(m_hStdoutHandle);
|
||||||
|
}
|
||||||
|
m_hStdoutHandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_fStdoutLogEnabled)
|
if (m_fStdoutLogEnabled)
|
||||||
{
|
{
|
||||||
m_Timer.CancelTimer();
|
m_Timer.CancelTimer();
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ public:
|
||||||
_In_ BOOL fAnonymousAuthEnabled,
|
_In_ BOOL fAnonymousAuthEnabled,
|
||||||
_In_ std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
|
_In_ std::map<std::wstring, std::wstring, ignore_case_comparer>& pEnvironmentVariables,
|
||||||
_In_ BOOL fStdoutLogEnabled,
|
_In_ BOOL fStdoutLogEnabled,
|
||||||
|
_In_ BOOL fDisableRedirection,
|
||||||
_In_ BOOL fWebSocketSupported,
|
_In_ BOOL fWebSocketSupported,
|
||||||
_In_ STRU *pstruStdoutLogFile,
|
_In_ STRU *pstruStdoutLogFile,
|
||||||
_In_ STRU *pszAppPhysicalPath,
|
_In_ STRU *pszAppPhysicalPath,
|
||||||
|
|
@ -253,6 +254,7 @@ private:
|
||||||
BOOL m_fBasicAuthEnabled;
|
BOOL m_fBasicAuthEnabled;
|
||||||
BOOL m_fAnonymousAuthEnabled;
|
BOOL m_fAnonymousAuthEnabled;
|
||||||
BOOL m_fDebuggerAttached;
|
BOOL m_fDebuggerAttached;
|
||||||
|
BOOL m_fEnableOutOfProcessConsoleRedirection;
|
||||||
|
|
||||||
STTIMER m_Timer;
|
STTIMER m_Timer;
|
||||||
SOCKET m_socket;
|
SOCKET m_socket;
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,12 @@ REQUESTHANDLER_CONFIG::Populate(
|
||||||
goto Finished;
|
goto Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = ConfigUtility::FindEnableOutOfProcessConsoleRedirection(pAspNetCoreElement, m_fEnableOutOfProcessConsoleRedirection);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
goto Finished;
|
||||||
|
}
|
||||||
|
|
||||||
Finished:
|
Finished:
|
||||||
|
|
||||||
if (pAspNetCoreElement != NULL)
|
if (pAspNetCoreElement != NULL)
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,12 @@ public:
|
||||||
return &m_struConfigPath;
|
return &m_struConfigPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
QueryEnableOutOfProcessConsoleRedirection()
|
||||||
|
{
|
||||||
|
return !m_fEnableOutOfProcessConsoleRedirection.Equals(L"false", 1);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -255,6 +261,7 @@ protected:
|
||||||
BOOL m_fWindowsAuthEnabled;
|
BOOL m_fWindowsAuthEnabled;
|
||||||
BOOL m_fBasicAuthEnabled;
|
BOOL m_fBasicAuthEnabled;
|
||||||
BOOL m_fAnonymousAuthEnabled;
|
BOOL m_fAnonymousAuthEnabled;
|
||||||
|
STRU m_fEnableOutOfProcessConsoleRedirection;
|
||||||
APP_HOSTING_MODEL m_hostingModel;
|
APP_HOSTING_MODEL m_hostingModel;
|
||||||
std::map<std::wstring, std::wstring, ignore_case_comparer> m_pEnvironmentVariables;
|
std::map<std::wstring, std::wstring, ignore_case_comparer> m_pEnvironmentVariables;
|
||||||
STRU m_struHostFxrLocation;
|
STRU m_struHostFxrLocation;
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,22 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||||
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.OutOfProcessFailedToStart(deploymentResult, "Wow!"), Logger);
|
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.OutOfProcessFailedToStart(deploymentResult, "Wow!"), Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewShim]
|
||||||
|
public async Task DisableRedirectionNoLogs()
|
||||||
|
{
|
||||||
|
var deploymentParameters = Fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess);
|
||||||
|
deploymentParameters.HandlerSettings["enableOutOfProcessConsoleRedirection"] = "false";
|
||||||
|
deploymentParameters.TransformArguments((a, _) => $"{a} ConsoleWriteSingle");
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
var response = await deploymentResult.HttpClient.GetAsync("Test");
|
||||||
|
|
||||||
|
StopServer();
|
||||||
|
|
||||||
|
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.OutOfProcessFailedToStart(deploymentResult, ""), Logger);
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
public async Task CaptureLogsForOutOfProcessWhenProcessFailsToStart30KbMax()
|
public async Task CaptureLogsForOutOfProcessWhenProcessFailsToStart30KbMax()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,55 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.OutOfProcess
|
||||||
Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode);
|
Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[MemberData(nameof(TestVariants))]
|
||||||
|
[RequiresNewShim]
|
||||||
|
public async Task ShutdownMultipleTimesWorks(TestVariant variant)
|
||||||
|
{
|
||||||
|
// Must publish to set env vars in web.config
|
||||||
|
var deploymentParameters = Fixture.GetBaseDeploymentParameters(variant);
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
// Shutdown once
|
||||||
|
var response = await deploymentResult.HttpClient.GetAsync("/Shutdown");
|
||||||
|
|
||||||
|
// Wait for server to start again.
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
// ANCM should eventually recover from being shutdown multiple times.
|
||||||
|
response = await deploymentResult.HttpClient.GetAsync("/HelloWorld");
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 10)
|
||||||
|
{
|
||||||
|
// Didn't restart after 10 retries
|
||||||
|
Assert.False(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown again
|
||||||
|
response = await deploymentResult.HttpClient.GetAsync("/Shutdown");
|
||||||
|
|
||||||
|
// return if server starts again.
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
// ANCM should eventually recover from being shutdown multiple times.
|
||||||
|
response = await deploymentResult.HttpClient.GetAsync("/HelloWorld");
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test failure if this happens.
|
||||||
|
Assert.False(true);
|
||||||
|
}
|
||||||
|
|
||||||
private static int GetUnusedRandomPort()
|
private static int GetUnusedRandomPort()
|
||||||
{
|
{
|
||||||
// Large number of retries to prevent test failures due to port collisions, but not infinite
|
// Large number of retries to prevent test failures due to port collisions, but not infinite
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue