2

I am starting a process (actually phantomjs) using c#, and am trying to pass information (a base64image string) via the standard output. Should the process succeed, everything goes well. Should the process fail (in this case because there is a javascript error in a page phantomjs is opening), it hangs indefinitely.

My code looks like this:

var path = Server.MapPath("phantomjs.exe");
var args = string.Join(" ", new[] { Server.MapPath(@"screenshot.js"), url });

var info = new ProcessStartInfo(path, args);
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;

var p = Process.Start(info);

// it hangs on the following line:
var base64image = p.StandardOutput.ReadToEnd();
bytes = Convert.FromBase64CharArray(base64image.ToCharArray(), 0, base64image.Length);

I am assuming that running any external process could lead to this problem. If that process does not finish properly (for whatever reason) then there will never be an output end to read to (maybe?).

What I would like to know is, how can I introduce a maximum timeout? Should the process succeed and exit in less than the timeout, great. If not, kill the process and do something else.

I have tried the following:

if (p.WaitForExit(30000))
{
    var base64image = p.StandardOutput.ReadToEnd();
    bytes = Convert.FromBase64CharArray(base64image.ToCharArray(), 0, base64image.Length);

    // do stuff with bytes
}
else
{
    p.Kill();

    // do something else
}

This worked when I was running a much simpler application (that simply wrote a number to the console every second for 60 seconds). When I tried with phantomjs, it fails (waiting 30 seconds) for cases that should work (and take much less than 30 seconds when I revert to my original code, or run it from the console).

Maybe phantomjs (or the js script I wrote) does not exit properly, but can the c# deal with all scenarios?

zod
  • 2,688
  • 5
  • 27
  • 49
  • possible duplicate of [c# ProcessStartInfo.Start - reading output but with a timeout](http://stackoverflow.com/questions/5718473/c-sharp-processstartinfo-start-reading-output-but-with-a-timeout) – sirdank Apr 29 '15 at 20:50

1 Answers1

1

You have to add a global error handler in your script. phantomjs won't exit by itself when there is a JavaScript execution error (parsing, exception, ...).Try by yourself in a simple script.

A very basic example is available here.

phantom.onError = function(msg, trace) {
    var msgStack = ['PHANTOM ERROR: ' + msg];
    if (trace && trace.length) {
        msgStack.push('TRACE:');
        trace.forEach(function(t) {
            msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function + ')' : ''));
        });
    }
    console.error(msgStack.join('\n'));
    phantom.exit(1);
};

In addition you can also add a page error handler.

page.onError = function(msg, trace) {
    var msgStack = ['ERROR: ' + msg];
    if (trace && trace.length) {
        msgStack.push('TRACE:');
        trace.forEach(function(t) {
            msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function + '")' : ''));
        });
    }
    console.error(msgStack.join('\n'));
};

Just note that phantom.error is invoked when there is a JavaScript execution error not caught by a WebPage#onError handler.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Cybermaxs
  • 24,378
  • 8
  • 83
  • 112
  • Thanks for this. I updated phantomjs and that also seemed to solve my problem (which I never fully understood). My question is more about safer ways to run processes in c# that don't rely on those process behaving correctly. – zod Jun 20 '13 at 10:01