how to controller (start/kill) a background process (server app) in ruby
Asked Answered
T

3

9

i'm trying to set up a server for integration tests (specs actually) via ruby and can't figure out how to control the process.

so, what i'm trying to do is:

  1. run a rake task for my gem that executes the integration specs
  2. the task needs to first start a server (i use webrick) and then run the specs
  3. after executing the specs it should kill the webrick so i'm not left with some unused background process

webrick is not a requirement, but it's included in the ruby standard library so being able to use it would be great.

hope anyone is able to help!

ps. i'm running on linux, so having this work for windows is not my main priority (right now).

Toulon answered 2/1, 2010 at 22:18 Comment(0)
A
14

The standard way is to use the system functions fork (to duplicate the current process), exec (to replace the current process by an executable file), and kill (to send a signal to a process to terminate it).

For example :

pid = fork do
  # this code is run in the child process
  # you can do anything here, like changing current directory or reopening STDOUT
  exec "/path/to/executable"
end

# this code is run in the parent process
# do your stuffs

# kill it (other signals than TERM may be used, depending on the program you want
# to kill. The signal KILL will always work but the process won't be allowed
# to cleanup anything)
Process.kill "TERM", pid

# you have to wait for its termination, otherwise it will become a zombie process
# (or you can use Process.detach)
Process.wait pid

This should work on any Unix like system. Windows creates process in a different way.

Actaeon answered 2/1, 2010 at 23:7 Comment(3)
great. thank you very much. while trying things out i had an almost identical "solution" which almost worked, but unfornately i can't figure out where it was different. also i needed to add a sleep after forking the process to wait until the server was available. thanks!Toulon
i was able to reproduce the difference. i ran Kernel#system instead of Kernel#exec. Kernel#exec "replaces the current process by running the given external command" where Kernel#system "executes the command in a subshell".Toulon
Can the child process stay alive even if the ruby script exits?Smallwood
S
2

I just had to do something similar and this is what I came up with. @Michael Witrant's answer got me started, but I changed some things like using Process.spawn instead of fork (newer and better).

# start spawns a process and returns the pid of the process
def start(exe)
    puts "Starting #{exe}"
    pid = spawn(exe)
    # need to detach to avoid daemon processes: http://www.ruby-doc.org/core-2.1.3/Process.html#method-c-detach
    Process.detach(pid)
    return pid
end

# This will kill off all the programs we started
def killall(pids)
  pids.each do |pid|
      puts "Killing #{pid}"
      # kill it (other signals than TERM may be used, depending on the program you want
      # to kill. The signal KILL will always work but the process won't be allowed
      # to cleanup anything)
      begin
        Process.kill "TERM", pid

        # you have to wait for its termination, otherwise it will become a zombie process
        # (or you can use Process.detach)
        Process.wait pid
      rescue => ex
        puts "ERROR: Couldn't kill #{pid}. #{ex.class}=#{ex.message}"
      end
  end
end

# Now we can start processes and keep the pids for killing them later
pids = []
pids << start('./someprogram')

# Do whatever you want here, run your tests, etc. 

# When you're done, be sure to kill of the processes you spawned
killall(pids)

That's about all she wrote, give it a try and let me know how it works.

Shampoo answered 8/10, 2014 at 17:34 Comment(0)
S
0

I have tried fork, but it has kind of problems when ActiveRecord is involved in both the processes. I would suggest Spawn plugin (http://github.com/tra/spawn). It does fork only but takes care of ActiveRecord.

Septemberseptembrist answered 3/1, 2010 at 9:32 Comment(1)
if you need ar, your solution might be the way to go. so thank you. but i don't really need to use ar.Toulon

© 2022 - 2024 — McMap. All rights reserved.