[Ruby 1.9][Windows] Sending Ctrl-C interrupt signal to a spawned subprocess - ruby

I have a main script in Ruby 1.9.3 running on Windows. It's will start another Ruby script that runs as a daemon, do its own stuff, then end the daemon by sending an "INT" signal. The main script and daemon don't otherwise do any data exchange.
The daemon itself can run as a standalone, and we terminate it with Ctrl-C. Here's the part that prepares it for the signal:
def setup_ctrl_c_to_quit
Thread.new do
trap("INT") do
puts "got INT signal"
exit
end
while true
sleep 1
end
end
end
I am currently having trouble having the main script launching and terminating the daemon. Currently, I can start the daemon through spawn and detach as such:
def startDaemon
#daemonPID = spawn("ruby c:/some_folder/daemon.rb", :new_pgroup=>true, :err=>:out)
puts "DaemonPID #{#daemonPID}"
daemonDetatch = Process.detach(#daemonPID)
puts "Detached Daemon . Entering sleep...."
sleep 15
puts "Is daemon detached thread alive? => #{daemonDetatch.alive?}"
puts "Attempt to kill daemon...."
Process.kill( "INT", #daemonPID )
sleep 5
puts "Is daemon detached thread still alive? => #{daemonDetatch.alive?}"
end
Ideally, the last puts statement should show daemonDetatch.alive? to be false. In reality, not only does daemonDetatch.alive? still ended up being true by the end, the daemon also can be found as still running in both the Task Manager and other 3rd party apps such as Process Explorer.
The first question I have is with the spawn(...) function. The official documentation said that :new_pgroup "is necessary for Process.kill(:SIGINT, pid) on the subprocess" send it determines whether the subprocess becomes a new group or not. I've toggled with this paramter, but it didn't seem to make a difference.
Also, I am planning to give this solution a try, which involves using the win32-process gem. I am just wondering if there are other solutions out there.
[Edit]
I have validated the PID of the daemon obtained in the main script, the daemon itself (with $$), and Process Explore, and they are all the same.
I have gotten suggestion from many others to just use "taskkill /f" to terminate the daemon. That will indeed end the daemon, but the daemon cannot trap the "TERM" or "KILL" signals the same way it traps "INT", meaning it will be unable to run its clean-up/quit routine.

Related

Ruby exucution stuck at system() line

This is my code snippet
def execution_start
puts "About to start"
system("appium")
puts "Done!!"
end
When executing this I see the output About to start, and appium server is launched. But after that, I do not see anything happening. It's stuck forever. Any idea?
system blocks until the command it runs has completed. To run a command and return immediately, use Process#spawn:
def execution_start
puts "About to start"
pid = Process.spawn("appium")
puts "Done!!"
end
You can then use the returned PID to monitor whether the process has finished executing, and with what exit code, later in your program.
(Note that, per the documentation, you need to Process#wait the PID eventually, or at least register disinterest using Process#detach to prevent the subprocess from becoming a zombie.)

Killing Threads in Ruby Shoes doesn't seem to work?

I try to make this piece of code works in Ruby Shoes, but I can't succeed to kill the thread named "airodump". Each time I click on the "stop scanning" button, it doesn't do anything :s
Thanks
button "scan networks" do
airodump = Thread.new do
`sudo airodump-ng --write tuto wlan0`
end
Thread.new do
button "Stop scanning" do
Thread.kill(airodump)
end
end
end
Thread killing (in any language) is a pretty limited operation. In your case, the thread is stuck in a blocking call - the call to the subshell - and therefore cannot be killed.
What you would need to do is kill the subprocess first. I don't know how to get the PID out of the backtick operator, so you would need to rather use Process.spawn (on ruby 1.9), gey the PID of the subprocess, and call Process.kill
I think the main problem is that you should use class variables so define
#airodump=Thread.new do
...
end
And than kill it by:
Thread.kill(#airodump)

Ruby run two processes, output results to terminal, and end safely

In Ruby, I'm running a system("command here") that is constantly watching changes for files, similar to tail. I'd like my program to continue to run and not halt at the system() call. Is there a way in Ruby to create another process so both can run independently, output results to the terminal, and then when you exit the program all processes the application created are removed?
Just combine spawn and waitall:
spawn 'sleep 6'
spawn 'sleep 8'
Process.waitall
You don't want to use system as that waits for the process to complete. You could use spawn instead and then wait for the processes (to avoid zombies). Then, when you want to exit, send a SIGTERM to your spawned processes. You could also use fork to launch your child processes but spawn is probably easier if you're using external programs.
You could also use process groups instead of tracking all the process IDs, then a single Process.kill('TERM', -process_group_id) call would take care of things. Your child processes should end up in the same process group but there is Process.setpgid if you need it.
Here's an example that uses fork (easier to get it all wrapped in one package that way).
def launch(id, sleep_for)
pid = Process.fork do
while(true)
puts "#{id}, pgid = #{Process.getpgid(Process.pid())}, pid = #{Process.pid()}"
sleep(sleep_for)
end
end
# No zombie processes please.
Process.wait(pid, Process::WNOHANG)
pid
end
# These just forward the signals to the whole process group and
# then immediately exit.
pgid = Process.getpgid(Process.pid())
Signal.trap('TERM') { Process.kill('TERM', -pgid); exit }
Signal.trap('INT' ) { Process.kill('INT', -pgid); exit }
launch('a', 5)
launch('b', 3)
while(true)
puts "p, pgid = #{Process.getpgid(Process.pid())}, pid = #{Process.pid()}"
sleep 2
end
If you run that in one terminal and then kill it from another (using the shell's kill command)you'll see that the children are also killed. If you remove the "forward this signal to the whole process group" Signal.trap stuff, then a simple SIGTERM will leave the children still running.
All of this assumes that you're working on some sort of Unixy system (such as Linux or OSX), YMMV anywhere else.
One more vote for using Spawn. We use it in Production a lot and it's very stable.

Where goes signal sent to process which called system?

Given a very simple ruby script:
child = fork do
system 'sleep 10000'
end
5.times do
sleep 1
puts "send kill to #{child}"
Process.kill("QUIT", child)
end
QUIT signal is just lost. Where does it go? Something with default handler which just ignores it?
How to send signal to all processes created by that fork? Is it possible to do that without searching for all child processes?
The problem is that the system call creates yet another child process running the given command in a subshell, so there are actually three processes running in your example. Additionally, the Ruby Kernel#system command is implemented via the standard C function system(3), which calls fork and exec to create the new process and (on most systems) ignores SIGINT and SIGQUIT, and blocks SIGCHLD.
If you simply call sleep(10000) instead of system("sleep 10000") then things should work as you expect. You can also trap SIGQUIT in the child to handle it gracefully:
child = fork do
Signal.trap("QUIT") { puts "CHILD: ok, quitting time!"; exit }
sleep(10000)
end
If you really need to use a "system" call from the child process then you might be better off using an explicit fork/exec pair (instead of the implicit ones in the system call), so that you can perform your own signal handling in the third forked child.
I think that you are sending signal to fork process corectly. I think that the problem is with the system command. System command creates new fork and waits until it ends and I think that this waiting is blocking your quit signal. If you run your example as test.rb you'll see three processes:
test.rb
test.rb
sleep 10000
If you send signal "TERM" or "KILL" instead of "QUIT" the second test.rb will die but sleep 10000 will continue!

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

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:
run a rake task for my gem that executes the integration specs
the task needs to first start a server (i use webrick) and then run the specs
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).
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.
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.
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.

Resources