Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run code when Signal is sent, but do not trap the signal in Ruby

Tags:

ruby

signals

I have code that is running on a server, before the server is hard shut down, a signal SIGTERM is sent to let my code know it needs to clean up. I want to run code when this happens and send the signal back to the same program so any other code that needs to clean up can do so. I do not want to trap the signal or change signal behavior, I only need to run something before the rest of my program interprets the SIGTERM.

Currently I can do something like

Signal.trap('TERM') do
  puts "Graceful shutdown"
  exit
end

but it doesn't work if multiple pieces of code in the same app try to do the same thing. For example:

Signal.trap('TERM') do
  puts "Graceful shutdown"
  exit
end

Signal.trap('TERM') do
  puts "Another graceful shutdown"
  exit
end

You will only ever see "Another graceful shutdown" and the first code block will not run.

Ideally I would be able to invoke current behavior with something like:

Signal.trap('TERM') do
  puts "another graceful shutdown"
  super
end

But this doesn't work for obvious reasons. So the question is this: how can I run code when i get a SIGTERM without trapping it and preventing other code from doing the same?

like image 578
Schneems Avatar asked Apr 10 '15 18:04

Schneems


1 Answers

Signal.trap returns the previous handler so you can do something like

def prepend_handler(signal, &handler)
  previous = Signal.trap(signal) do
    previous = -> { raise SignalException, signal} unless previous.respond_to?(:call)
    handler.call(previous)
  end
end

prepend_handler("TERM") do |old|
  do_something
  old.call
end

The respond_to? business is because a handler is either a callable or a string (the string values are documented here). Unless you use those string handlers yourself you are most likely to run into 'DEFAULT', i.e. the default ruby behaviour

like image 167
Frederick Cheung Avatar answered Sep 28 '22 04:09

Frederick Cheung