twenty20
twenty20

Reputation: 59

Fork a child process, and capture any stdout and stderr?

My below code example runs a command, e.g., ls <file> and captures stdout and stderr ( as well as the process exit status ).

However, if for example the command were to hang, then the ruby program will be "stuck" waiting for the command to finish, ( this can be seen for example if running sleep).

To avoid that possibility, I think what I need to do is fork a child process, ( so any "stuck" child process will not keep the ruby program "waiting" ).

However, I'm not sure how to capture the stdout and stderr from a forked child process, is this even possible ?

( for reasons I'd also like to be able to do this within the ruby std libs and not have dependency on any extra gem/s. Also, this is just for ruby, not rails )

edit: To help clarify - Trying to understand if there is a way to fork a child process, ( so there is no blocking until the child is done ), and still have the ruby program capture the stdout, stderr when the child process exits.

#!/bin/env ruby

require 'open3'
require 'logger'

logger = Logger.new('./test_open3.log')
files = ['file1','file2','file3']

files.each do |f|
  stdout, stderr, status = Open3.capture3("ls #{f}")
  logger.info(stdout)
  logger.info(stderr)
  logger.info(status)
end

Upvotes: 1

Views: 1019

Answers (1)

twenty20
twenty20

Reputation: 59

Following the suggestion in the comments to use threads, I found that this gave me what I was looking for:

#!/bin/env ruby

require 'open3'
require 'logger'
require 'thread'

logger = Logger.new('./test_threads_open3.log')
files = ['file1','file2','file3']
threads = []

files.each_with_index do |f, i|
  threads << Thread.new(f, i) do
    puts "Thread #{i} is running"
    stdout, stderr, status = Open3.capture3("ls #{f}")
    logger.info(stdout)
    logger.info(stderr)
    logger.info(status)
   end
 end
threads.each { |t| t.join }

This creates an array of threads each with the block of code, and then last line, each thread in the array is run.

It probably requires some extra code to manage and limit the number of threads that can be run at a time, so as to be safer, maybe by using a queue/worker feature.

( This post also touches on the topic of the join method - Thread.join blocks the main thread )

Upvotes: 1

Related Questions