At the moment, I am using CTRL+C to exit rake preview. Is there a graceful way to do so?
From the source
trap("INT") {
[jekyllPid, compassPid].each { |pid| Process.kill(9, pid) rescue Errno::ESRCH }
exit 0
}
Only when you change the script you could make it respond to something else. But CTRL+C is just fine.
trap("INT") does the magic: as soon as Ctrl+C is pressed the part between the curly braces is executed. That code simply kills all preview processes.
Related
I want to create a Ruby script, which will start like this:
$ ruby script.rb &
Then, I will close the console and it must stay alive, working in the background. At the moment I have to run it like this, in order to achive that:
$ nohup ruby script.rb &
I want to get rid of nohup and deal with SIGHUP directly inside the script -- simply ignore it. Is it possible?
Sure, just Signal.trap HUP signal:
def do_fork
$pid = fork do
Signal.trap("HUP") do
puts "Received HUP, ignoring..."
end
Signal.trap("TERM") do
puts "Received TERM, terminating..."
exit(0)
end
while true do sleep(10_000) end
end
Process.detach($pid)
end
do_fork
Copy the code above to some file and run it with ruby file.rb to see it ignores kill -HUP pid and closes on kill -TERM pid.
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.
Here's a simplified version of some code I wrote:
class InfiniteLoop
def run
trap('SIGTERM') do
puts 'exiting'
exit
end
loop {}
end
end
If I run:
InfiniteLoop.new.run
I can ctrl+c and get:
exiting
However, when I do this:
t = Thread.new { InfiniteLoop.new.run }
sleep 1
t.terminate
I don't see:
exiting
Can someone point me in the right direction here? I'd like to have the same behavior when terminating the thread.
If you are not sending a SIGTERM signal (via ctrl+c) the trap block is not executed.
See also the Kernel method:
at_exit { puts 'exiting' }
trap('SIGTERM') will only respond to the signals sent from OS land.
Thread#terminate is ruby code that will kill the thread.
I don't know of a way to specify behavior for a thread to take before it is killed. That might be interesting. But I don't think it exists, because the semantics of Thread#kill/terminate/join wouldn't really allow that.
Try trap("EXIT"). SIGTERM is sent by ctrl-C or a kill command. From the ruby docs:
The special signal name “EXIT” or signal number zero will be invoked just prior to program termination.
When I Ctrl C my program on linux I often get output that looks similar to a stack-dump (a crash).
Can I catch the Ctrl-C signal and exit gracefully?
Thanks!
You can trap signals with Kernel.trap:
trap('INT') do
# exit gracefully
end
I have a long-running process with some child processes that must be restarted if they exit. To handle clean restarts of these child processes, I trap the exit signal with
trap("CLD") do
cpid = Process.wait
... handle cleanup ...
end
The long-running process occasionally needs to invoke 'curl' using a backquote as in
`/usr/bin/curl -m 60 http://localhost/central/expire`
The problem is that the backquote invocation is causing me to get a SIGCHLD and making my trap fire. This then gets stuck in the CLD trap because Process.wait does not finish. If there happen to be no (non-backquote) child processes at that time, the Process.wait instead gives an Errno::ECHILD exception.
I can circumvent this problem by wrapping the backquote call with this line before:
sig_handler = trap("CLD", "IGNORE") # Ignore child traps
and this line after the backquote invocation:
trap("CLD", sig_handler) # replace the handler
but this means that I may miss a signal from the (non-backquote) child processes during that window, so I'm not really happy with that.
So, is there a better way to do this?
(I am using ruby 1.9.1p243 on GNU/Linux 2.6.22.6 if it matters)
Update:
The code below illustrates the problem (and my current solution for it).
There seems to be some strange timing issue here since I don't always get the ECHILD exception. But just once is enough to mess things up.
#!/usr/bin/env ruby
require 'pp'
trap("CLD") do
cpid = nil
begin
puts "\nIn trap(CLD); about to call Process.wait"
cpid = Process.wait
puts "In trap(CLD); Noting that ssh Child pid #{cpid}: terminated"
puts "Finished Child termination trap"
rescue Errno::ECHILD
puts "Got Errno::ECHILD"
rescue Exception => excep
puts "Exception in CLD trap for process [#{cpid}]"
puts PP.pp(excep, '')
puts excep.backtrace.join("\n")
end
end
#Backtick problem shown (we get an ECHILD most of the time)
puts "About to invoke backticked curl"
`/usr/bin/curl -m 6 http://developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo`
sleep 2; sleep 2 # Need two sleeps because the 1st gets terminated early by the trap
puts "Backticked curl returns"
# Using spawn
puts "About to invoke curl using spawn"
cpid = spawn("/usr/bin/curl -m 6 http://developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo")
puts "spawned child pid is #{cpid} at #{Time.now}"
Start monitored subprocesses from a subprocess
Just start your tracked and monitored children from a child of your main process that never exits. That way it won't notice the backtick children exiting...
And if you do this, you could avoid the use of SIGCHLD entirely, as you could just use a loop with a wait in it to notice children exit events.
Other ideas:
ignore one SIGCHLD every time you execute a backtick command. ISTM that you might ignore a "real" SIGCHLD by accident this way, but that won't matter, because you would then get a "spurious" one that you would process.