What may be the reason of my process hanging while waiting for exit?
This code has to start powershell script which inside performs many action e.g start recompiling
For the benefit of readers I'm going to divide this to 2 Sections
Section A: Problem & how to handle similar scenarios
Section B: Problem recreation & Solution
When this problem happens - process appears in task manager, then after 2-3sec disappears (its fine), then it waits for timeout and then exception is thrown System.InvalidOperationException: Process must exit before requested information can be determined.
& See Scenario 4 below
In your code:
Process.WaitForExit(ProcessTimeOutMiliseconds); With this you're waiting for Process to Timeout or Exit, which ever takes place first. OutputWaitHandle.WaitOne(ProcessTimeOutMiliseconds)anderrorWaitHandle.WaitOne(ProcessTimeOutMiliseconds); With this you're waiting for OutputData & ErrorData stream read operation to signal its complete Process.ExitCode == 0 Gets status of process when it exitedDifferent settings & their caveats:
ObjectDisposedException()Process.ExitCode resulting in the error System.InvalidOperationException: Process must exit before requested information can be determined.I have tested this scenario over a dozen times and works fine, following settings have been used while testing
Updated Code
.
.
.
process.BeginOutputReadLine();
process.BeginErrorReadLine();
//First waiting for ReadOperations to Timeout and then check Process to Timeout
if (!outputWaitHandle.WaitOne(ProcessTimeOutMiliseconds) && !errorWaitHandle.WaitOne(ProcessTimeOutMiliseconds)
&& !process.WaitForExit(ProcessTimeOutMiliseconds) )
{
//To cancel the Read operation if the process is stil reading after the timeout this will prevent ObjectDisposeException
process.CancelOutputRead();
process.CancelErrorRead();
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Timed Out");
Logs = output + Environment.NewLine + error;
//To release allocated resource for the Process
process.Close();
return (false, logs);
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Completed On Time");
Logs = output + Environment.NewLine + error;
ExitCode = process.ExitCode.ToString();
// Close frees the memory allocated to the exited process
process.Close();
//ExitCode now accessible
return process.ExitCode == 0 ? (true, logs) : (false, logs);
}
}
finally{}
EDIT:
After hours of playing around with MSBuild I was finally able to reproduce the issue at my system
MSBuild has
-m[:number]switch which is used to specify the maximum number of concurrent processes to use when building.When this is enabled, MSBuild spawns a number of nodes that lives on even after the Build is complete. Now,
Process.WaitForExit(milliseconds)would wait never exit and eventually timeout
I was able to solve this in couple of ways
Spawn MSBuild process indirectly through CMD
$path1 = """C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe"" ""C:\Users\John\source\repos\Test\Test.sln"" -maxcpucount:3"
$cmdOutput = cmd.exe /c $path1 '2>&1'
$cmdOutput
Continue to use MSBuild but be sure to set the nodeReuse to False
$filepath = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe"
$arg1 = "C:\Users\John\source\repos\Test\Test.sln"
$arg2 = "-m:3"
$arg3 = "-nr:False"
Start-Process -FilePath $filepath -ArgumentList $arg1,$arg2,$arg3 -Wait -NoNewWindow
Even If parallel build is not enabled, you could still prevent your process from hanging at WaitForExit by launching the Build via CMD & therefore you do not create a direct dependency on Build process
$path1 = """C:\....\15.0\Bin\MSBuild.exe"" ""C:\Users\John\source\Test.sln"""
$cmdOutput = cmd.exe /c $path1 '2>&1'
$cmdOutput
The 2nd approach is preferred since you do not want too many MSBuild nodes to be lying around.