What's the difference between Process.fork and Process.spawn in Ruby 1.9.2
What's the difference between Process.fork and the new Process.spawn methods in Ruby 1.9.2
Process.fork
allows you to run ruby code in another process. Process.spawn
allows you to run another program in another process. Basically Process.spawn
is like using Process.fork
and then calling exec
in the forked process, except that it gives you more options.
and which one is better to run another program in a subprocess?
If you need backwards compatibility, use fork
+ exec
as spawn
is not available in 1.8. Otherwise use spawn
since running another program in a subprocess is exactly what spawn
is made for.
As far as I understand Process.fork accepts block of code and Process.spawn takes a system command plus some other parameters.
Exactly.
When I should use one instead of the other?
Use fork
if you need to run arbitrary ruby code in a separate process (you can't do that with spawn
). Use spawn
if you need to invoke an application in a subprocess.
Fork child process with timeout and capture output
You can use IO.pipe
and tell Process.spawn
to use the redirected output without the need of external gem.
Of course, only starting with Ruby 1.9.2 (and I personally recommend 1.9.3)
The following is a simple implementation used by Spinach BDD internally to capture both out and err outputs:
# stdout, stderr pipes
rout, wout = IO.pipe
rerr, werr = IO.pipe
pid = Process.spawn(command, :out => wout, :err => werr)
_, status = Process.wait2(pid)
# close write ends so we could read them
wout.close
werr.close
@stdout = rout.readlines.join("\n")
@stderr = rerr.readlines.join("\n")
# dispose the read ends of the pipes
rout.close
rerr.close
@last_exit_status = status.exitstatus
The original source is in features/support/filesystem.rb
Is highly recommended you read Ruby's own Process.spawn documentation.
Hope this helps.
PS: I left the timeout implementation as homework for you ;-)
TERM signal to forked process doesn't work
The reason why it did not work as expected was that the kill was delivered before the exec commenced. Introducing a little sleep before delivering the kill ensures that the program will behave as expected.
Ruby: running external processes in parallel and keeping track of exit codes
Try:
statuses = pids.map { |pid| Process.wait(pid, 0); $? }
This waits for each of the process ids to finish, and checks for the result status set in $?
for each process
spawning a command prompt in a different process and sending/receiving commands on Windows
Here an example using IO.popen in windows, imo if it works with the stdlib don't use gems
IO.popen("other_program", "w+") do |pipe|
pipe.puts "here, have some input"
pipe.close_write # If other_program process doesn't flush its output, you probably need to use this to send an end-of-file, which tells other_program to give us its output. If you don't do this, the program may hang/block, because other_program is waiting for more input.
output = pipe.read
end
# You can also use the return value from your block. (exit code stored in $? as usual)
output = IO.popen("other_program", "w+") do |pipe|
pipe.puts "here, have some input"
pipe.close_write
pipe.read
end
What's the difference between :new, :collection and :member routes?
The difference is the URL generated.
Let's guess three resources :
map.resources :users, :collection => { :rss => :get }
map.resources :users, :member => { :profile => :get }
map.resources :users, :new => { :draft => :get }
The first route will create :
/users/rss
With nothing between the controller name and the action name. We don't need any other parameter to get the user's list rss feed.
The second one will create the action "profile" as a member of the object. So we'll have :
/users/1/profile
The "1" is the user's to_param
. We need a user's id to display a profile.
The third one will create the action "draft" as a member of the new action. So we'll have :
/users/new/draft
The "draft" action displays a draft of the user before accepting its creation.
So that's the difference between :collection, :member and :new. Every of them creates different routes, each one with their own purpose.
Kill process launched via thread
You can use Process.spawn
instead of threads and backticks:
class TestServer < MiniTest::Unit::TestCase
def setup
@pid = spawn "#{MY_COMMAND}"
end
def test_aaa
# my test code
end
def teardown
Process.kill('TERM', @pid) if @pid
end
end
Related Topics
How to Track Down a Memory Leak in My Ruby Code
How to Use "Puts" to the Console Without a Line Break in Ruby on Rails
Conditional Key/Value in a Ruby Hash
Ruby/Rails - .Each Iterator Is Printing Entire Array at the End of the Loop
Sprockets::Circulardependencyerror in Store#Index
How to Override a Column in Rails Model
Why Are My Bigdecimal Objects Initialized with Unexpected Rounding Errors
Difference Between '%{}', '%Q{}', '%Q{}' in Ruby String Delimiters
Rails 3.1 with Postgresql: Group by Must Be Used in an Aggregate Function
How to Determine the Md5 Digest of a Given Asset in the Rails Asset Pipeline
Fastest Way to Check If a String Matches a Regexp in Ruby
Passing Headers and Query Params in Httparty
Attr_Accessor Strongly Typed Ruby on Rails
Error Running '_Rvm_Make Install'
Suppressing the Output of a Command Run Using 'System' Method While Running It in a Ruby Script