The code below is the method I'm using to execute CMD commands. On the production server, it sometimes gets stuck for no apparent reason, even though I have already applied a timeout method. Despite this, it still occasionally gets stuck.
using System.Diagnostics;
using System.Text;
namespace SharedLibraries.Helpers
{
public class CommandExecutor
{
private readonly Logger _logger;
private const int DefaultTimeoutMilliseconds = 10000;
public CommandExecutor(Logger logger)
{
_logger = logger;
}
public bool ExecuteCommand(string command, out string result, int timeoutMilliseconds = DefaultTimeoutMilliseconds)
{
Process? process = new()
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/c {command}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
}
};
StringBuilder? output = new();
StringBuilder? error = new();
try
{
_logger.Log(message: $"Executing command: '{command}'", LogLevel.INFO);
process.OutputDataReceived += (object sender, DataReceivedEventArgs args) => { output.AppendLine(args.Data); };
process.ErrorDataReceived += (object sender, DataReceivedEventArgs args) => { error.AppendLine(args.Data); };
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (!process.WaitForExit(milliseconds: timeoutMilliseconds))
{
process.Kill();
result = "Command execution timed out.";
_logger.Log(message: $"Command timeout. Command: '{command}', Timeout: {timeoutMilliseconds}ms", LogLevel.ERROR);
return false;
}
process.WaitForExit();
string errorOutput = error.ToString().Trim();
if (process.ExitCode != 0 || !string.IsNullOrEmpty(value: errorOutput))
{
result = $"Command execution failed with exit code {process.ExitCode}:\n{errorOutput}";
_logger.Log(message: $"Command execution failed. Command: '{command}', Exit Code: {process.ExitCode}, Error: {errorOutput}", LogLevel.ERROR);
return false;
}
result = output.ToString().Trim();
_logger.Log(message: $"Command executed successfully. Command: '{command}', Result:\n{result}", LogLevel.INFO);
return true;
}
catch (Exception ex)
{
result = $"Error executing command: {ex.Message}";
_logger.Log(message: $"Exception during command execution. Command: '{command}', Exception: {ex}", LogLevel.ERROR);
return false;
}
}
}
}
Can anyone help me understand what's going on and suggest a method to improve the timeout mechanism? I'm looking for a solution that will allow the system to return 'false' when it becomes stuck.