Open3 and background processes

Hi all,

I've got a poor man's init script where I'm firing off a Ruby process
in the background if it's not already running.

If the process fails, no problemo. The process I called dies, I pull
the error from the stderr handle via readlines, and fire off an email
to myself. But if the process succeeds, IO#readlines hangs because
there's no data to be read, so it just hangs there waiting for it.

One solution I came up with was to wrap the IO#readlines in a timeout,
but that feels clunky. Is there a better way to do this?

require 'open3'
require 'timeout'

program = File.join(Dir.pwd, "miniserver.rb")

cmd = "ruby #{program} &"

Open3.popen3(cmd) do |stdin, stdout, stderr|
   begin
      # Better way?
      Timeout.timeout(2){
         error = stderr.readlines
      }
   rescue Timeout::Error
     puts "Timeout"
     break
   end

   puts error.join("\n") if error
end

puts "Done"

Where "miniserver.rb" is just a simple loop/print/sleep program. I
thought there was a way to peek ahead on an IO object to see if any
data is available on the handle before attempting to read it, but
perhaps I'm glossing over the appropriate method.

Suggestions?

Thanks,

Dan

IO.readlines will try to read out everything until EOF, hence it "hangs" for long running background processes. Can you use IO.readline instead and modify your spawned program to output a one line message to indicate success? Then it will catch both errors and successful runs.

Gennady.

···

-----Original Message-----
From: Daniel Berger [mailto:djberg96@gmail.com]
Sent: Tuesday, August 26, 2008 12:28 PM
To: ruby-talk ML
Subject: open3 and background processes

Hi all,

I've got a poor man's init script where I'm firing off a Ruby process
in the background if it's not already running.

If the process fails, no problemo. The process I called dies, I pull
the error from the stderr handle via readlines, and fire off an email
to myself. But if the process succeeds, IO#readlines hangs because
there's no data to be read, so it just hangs there waiting for it.

One solution I came up with was to wrap the IO#readlines in a timeout,
but that feels clunky. Is there a better way to do this?

require 'open3'
require 'timeout'

program = File.join(Dir.pwd, "miniserver.rb")

cmd = "ruby #{program} &"

Open3.popen3(cmd) do |stdin, stdout, stderr|
   begin
      # Better way?
      Timeout.timeout(2){
         error = stderr.readlines
      }
   rescue Timeout::Error
     puts "Timeout"
     break
   end

   puts error.join("\n") if error
end

puts "Done"

Where "miniserver.rb" is just a simple loop/print/sleep program. I
thought there was a way to peek ahead on an IO object to see if any
data is available on the handle before attempting to read it, but
perhaps I'm glossing over the appropriate method.

Suggestions?

Thanks,

Dan

Ah, ok. This seems to work fine:

program = File.join(Dir.pwd, "miniserver.rb")

cmd = "ruby #{program} &"

Open3.popen3(cmd) do |stdin, stdout, stderr|
   # Use readline, since readlines waits until EOF
   error = stderr.readline

   if error
      error = [error] << stderr.readlines # Get the rest
   end

   puts error if error
end

puts "Done"

Many thanks,

Dan

···

On Aug 26, 1:37 pm, Gennady Bystritsky <Gennady.Bystrit...@quest.com> wrote:

IO.readlines will try to read out everything until EOF, hence it "hangs" for long running background processes. Can you use IO.readline instead and modify your spawned program to output a one line message to indicate success? Then it will catch both errors and successful runs.

From: Daniel Berger [mailto:djberg96@gmail.com]
Sent: Tuesday, August 26, 2008 1:09 PM
To: ruby-talk ML
Subject: Re: open3 and background processes

> IO.readlines will try to read out everything until EOF, hence it
"hangs" for long running background processes. Can you use IO.readline
instead and modify your spawned program to output a one line message to
indicate success? Then it will catch both errors and successful runs.

Ah, ok. This seems to work fine:

program = File.join(Dir.pwd, "miniserver.rb")

cmd = "ruby #{program} &"

Open3.popen3(cmd) do |stdin, stdout, stderr|
   # Use readline, since readlines waits until EOF
   error = stderr.readline

The problem here is that if your miniserver.rb does not output anything to stderr in case of no error, stderr.readline will hang as well until it gets a newline. What I meant in my previous reply is that miniserver.rb must output something like "SUCCESS" to stderr so that you can test for this in popen3 block:

     error = stderr.readline
     unless error.chomp == "SUCCESS
       # process errors here
       ...
     end

···

-----Original Message-----
On Aug 26, 1:37 pm, Gennady Bystritsky <Gennady.Bystrit...@quest.com> > wrote:

   if error
      error = [error] << stderr.readlines # Get the rest
   end

   puts error if error
end

puts "Done"

Many thanks,

Dan