0

I am trying to run a process and read its stdoutput and stderror from a .net6 console app. The code:

public Process Run(string command, string args)
{
    var psi = new ProcessStartInfo
        {
            FileName = command,
            Arguments = args,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true
        };

    var p = new System.Diagnostics.Process { StartInfo = psi, EnableRaisingEvents = true };

    p.ErrorDataReceived += (sender, e) => ...
    p.OutputDataReceived += (sender, e) => ...
    p.Exited += async (sender, e) =>
        {
            // this allows to wait until we read both StandardOutput and StandardError asynchronously; without it we get more stdOut data after Exited event...
            // https://stackoverflow.com/a/17600012/5033397
            await p.WaitForExitAsync();
            p.Dispose();
        };

    p.Start();
    p.BeginOutputReadLine();
    p.BeginErrorReadLine();

    return p;
}

It works 99% of the time, but I am getting this error intermittently (might happen once every few hours or so while the app is running on a server):

System.InvalidOperationException: StandardError has not been redirected.
at System.Diagnostics.Process.BeginErrorReadLine()
at ProcessRunner.Run(String command, String args) in /app/ProcessRunner.cs:line 88

This happens both Windows and Linux. Processes being executed with code above:

  • iostat
  • typeperf
  • ffprobe
  • ffmpeg

What could be wrong with this setup?

andy250
  • 19,284
  • 2
  • 11
  • 26
  • I think you need a 'p.WaitForExit();' – Paul Sinnema Mar 22 '22 at 13:20
  • @PaulSinnema I dont want to block the thread to wait for exit. I have `await p.WaitForExitAsync` in the exited event handler. – andy250 Mar 22 '22 at 15:25
  • When you exit the `Run` method the `p` no longer exists (what do you do with the returned value?). My guess is that at that moment the output is redirected back to the default. Make your `Run` a `Task` and `await` the result. – Paul Sinnema Mar 23 '22 at 08:33
  • @PaulSinnema I dont actually use p later on. I don't agree with "p no longer exists" - it does exist, event handlers are executed and also p is disposedi in Exited handler - long after the return from method `Run` (some of these processes take 5-10 seconds to complete). Though I can try rewriting the entire thing to await the p outside of Exit event. But still - this breaks only occasionally... – andy250 Mar 23 '22 at 10:29
  • If there is no reference to `p` than the `GC` will clean it up. There is no guarantee when this will happen other than calling the `GC` yourself. Otherwise it can happen immediately or take seconds before that happens. I still think that the clean up of `p` is the problem. – Paul Sinnema Mar 23 '22 at 11:11
  • I don't agree as the exception is thrown in line `p.BeginErrorReadLine();` before the method returns. – andy250 Mar 24 '22 at 06:59

0 Answers0