Skip to content

Make stdout/stderr redirection thread timeout configurable #49942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
#include "StdWrapper.h"
#include "ntassert.h"
#include "StringHelpers.h"

#define LOG_IF_DUPFAIL(err) do { if (err == -1) { LOG_IF_FAILED(HRESULT_FROM_WIN32(_doserrno)); } } while (0, 0);
#define LOG_IF_ERRNO(err) do { if (err != 0) { LOG_IF_FAILED(HRESULT_FROM_WIN32(_doserrno)); } } while (0, 0);

#include "Environment.h"

StandardStreamRedirection::StandardStreamRedirection(RedirectionOutput& output, bool commandLineLaunch) :
m_output(output),
Expand All @@ -23,6 +20,28 @@ StandardStreamRedirection::StandardStreamRedirection(RedirectionOutput& output,
m_commandLineLaunch(commandLineLaunch)
{
TryStartRedirection();

// Allow users to override the default termination timeout for the redirection thread.
auto timeoutMsStr = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_OUTPUT_REDIRECTION_TERMINATION_TIMEOUT_MS");
if (timeoutMsStr.has_value())
{
try
{
int timeoutMs = std::stoi(timeoutMsStr.value());
if (timeoutMs > 0 && timeoutMs <= PIPE_OUTPUT_THREAD_TIMEOUT_MS_MAX)
{
m_terminationTimeoutMs = timeoutMs;
}
else
{
LOG_WARN(L"ASPNETCORE_OUTPUT_REDIRECTION_TERMINATION_TIMEOUT_MS must be an integer between 0 and 1800000. Ignoring.");
}
}
catch (...)
{
LOG_WARN(L"ASPNETCORE_OUTPUT_REDIRECTION_TERMINATION_TIMEOUT_MS must be an integer between 0 and 1800000. Ignoring.");
}
}
}

StandardStreamRedirection::~StandardStreamRedirection() noexcept(false)
Expand Down Expand Up @@ -80,8 +99,6 @@ void StandardStreamRedirection::Start()
// be thrown away.
void StandardStreamRedirection::Stop()
{
DWORD dwThreadStatus = 0;

if (m_disposed)
{
return;
Expand Down Expand Up @@ -126,12 +143,13 @@ void StandardStreamRedirection::Stop()
}

// GetExitCodeThread returns 0 on failure; thread status code is invalid.
DWORD dwThreadStatus = 0;
if (m_hErrThread != nullptr &&
!LOG_LAST_ERROR_IF(!GetExitCodeThread(m_hErrThread, &dwThreadStatus)) &&
dwThreadStatus == STILL_ACTIVE)
{
// Wait for graceful shutdown, i.e., the exit of the background thread or timeout
if (WaitForSingleObject(m_hErrThread, PIPE_OUTPUT_THREAD_TIMEOUT) != WAIT_OBJECT_0)
if (WaitForSingleObject(m_hErrThread, m_terminationTimeoutMs) != WAIT_OBJECT_0)
{
// If the thread is still running, we need kill it first before exit to avoid AV
if (!LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@

class StandardStreamRedirection : NonCopyable
{
// Timeout to be used if a thread never exits
#define PIPE_OUTPUT_THREAD_TIMEOUT 2000
#define PIPE_READ_SIZE 4096
// Default timeout for the redirection thread to exit before it is forcefully terminated
// This can be overridden with ASPNETCORE_OUTPUT_REDIRECTION_TERMINATION_TIMEOUT_MS
static constexpr int PIPE_OUTPUT_THREAD_TIMEOUT_MS_DEFAULT = 2000;

// Maximum allowed timeout value
static constexpr int PIPE_OUTPUT_THREAD_TIMEOUT_MS_MAX = 1800000; // 30 minutes

// Size of the buffer used to read from the pipe
static constexpr int PIPE_READ_SIZE = 4096;

public:
StandardStreamRedirection(RedirectionOutput& output, bool commandLineLaunch);
Expand Down Expand Up @@ -63,4 +69,5 @@ class StandardStreamRedirection : NonCopyable
std::unique_ptr<StdWrapper> stdoutWrapper;
std::unique_ptr<StdWrapper> stderrWrapper;
RedirectionOutput& m_output;
int m_terminationTimeoutMs = PIPE_OUTPUT_THREAD_TIMEOUT_MS_DEFAULT;
};