Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logic to kill a process within a time limit

I want to ensure that my logic is correct here. I want to run a process for timeout seconds, if it runs for longer it should be immediately killed.

The completed flag should reliably indicate whether the process completed as intended, e.g was not killed, and did not crash or throw an exception.

Also, I am not positive if the check to process.HasExited is correct. If process.WaitForExit() returns false and Kill() succeeds, then will process.HasExited always be true? That would be my assumption but I wanted to confirm. Also, what if anything can be done if Kill() fails, besides just logging?

        using (process = new Process())
        {
            process.EnableRaisingEvents = true;
            process.OutputDataReceived += new DataReceivedEventHandler(OnOutputDataReceived);
            process.ErrorDataReceived += new DataReceivedEventHandler(OnErrorDataReceived); 
            process.Exited += new EventHandler(OnExited);

            process.StartInfo = startInfo;
            process.Start();

            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            if (!process.WaitForExit(timeout))
            {
                try
                {
                    process.Kill(); 
                }
                catch (Exception e)
                {
                    LogError(e, MethodBase.GetCurrentMethod());
                }
                finally
                {
                    this.completed = false;
                }
            }
            else
            {
                if (process.HasExited)
                {
                    this.code = process.ExitCode; 
                    this.completed = true;
                }
                else
                {
                    this.completed = false; 
                }
            }
        }
like image 819
Sean Thoman Avatar asked Feb 15 '23 06:02

Sean Thoman


2 Answers

Yes, the HasExited will always be true in your case.

According to MSDN,

"A value of true for HasExited indicates that the associated process has terminated, either normally or abnormally.[...]A process can terminate independently of your code. If you started the process using this component, the system updates the value of HasExited automatically, even if the associated process exits independently."

However, if your process crashes and terminates before your timeout, then your code will set it as completed anyway. Maybe you should check the exit code, but it can have different meanings for each process:

if (process.ExitCode != 0)
{
    this.completed = false;
}

For crashes, there are some approaches here and here, but generally you can't detect crashes for all processes.

like image 150
natenho Avatar answered Feb 17 '23 21:02

natenho


We use the following in a .net console app

private void InitTimer()
{
    double lInterval = Convert.ToDouble(AppSettings("MaxExecutionTime"));
    lInterval = lInterval * 60 * 1000;
    tm = new System.Timers.Timer(lInterval); // global timer object
    tm.Elapsed += OnTimedEvent;
    tm.Enabled = true;
}

public void ThreadProc(object stateinfo)
{
    // set error code here
    Environment.Exit(0);
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
   Threading.ThreadPool.QueueUserWorkItem(new Threading.WaitCallback(ThreadProc));
}
like image 30
lcryder Avatar answered Feb 17 '23 21:02

lcryder