Search code examples
rubyspawn

Process.spawn (Ruby 1.9.x): How to check if spawning was successful and detect errors?


Using a cross-platform solution (GNU/Linux, Windows), I want to spawn an external program in the background, capture it's pid and later on stop the program via the stored pid.

Consider this code in Ruby 1.9.x:

pid = Process.spawn("xxx")
puts pid

stdout/stderr:

8117
sh: 1: xxx: not found

No exception is thrown, and I don't see any way to detect the fact that the spawn was not successful (xxx is not a valid command).

What is the best way to detect that this spawn was not successful?


Solution

  • Process#spawn returns a process ID. If you get a process ID back, then technically the function itself did not fail. In Ruby >= 2.0.0, Process#spawn will throw Errno::ENOENT if it fails to find the command. As ruby 1.9 is unsupported, the best solution is to upgrade ruby.

    A hack which may help would be to test if the process is actually running after the call returns. Sadly, this will be platform specific.

    pid = Process.spawn("xxx")
    case RUBY_PLATFORM
    when /linux/i
      success = File.exist?("/proc/#{pid}")
    when /windows/i
      # use win32api gem, Windows API call EnumProcesses
    else
      # ?  
    end
    

    Unfortunately, if the process finishes by the time you test for its existence, you can't tell. You probably want to check for its results (whatever it does) to see if it did it also.

    Another approach, if you control the program being launched, is to open a named pipe before launching it and have it send your ruby program a message over the pipe that it is running. You can then read from the pipe after the spawn call in a non-blocking way and use Timeout to prevent it from blocking forever. A simpler, less clean approach would be to have that program write something deterministic to a file that you can use a simple File.exist? test on to see if its there.