class RackRabbit::Signals

Public Class Methods

new() click to toggle source

The RackRabbit server process has a single primary thread, but it doesn't actually need to do any work once it has spun up the worker processes. I need it to hibernate until one (or more) signal event's occurs.

Originally I tried to use the standard Thread::Queue, it uses a Mutex to perform a blocking pop on the Queue. However Ruby (2.x) won't let the last active thread hibernate (it's overly aggressive at deadlock prevention)

So, instead of using a Mutex based Queue, I can use a blocking select on an IO pipe, then when the signal handler pushes into the Queue it can also write to the pipe in order to “awaken” the primary thread.

FYI: this is the same underlying idea that is used by the Unicorn master

process, I've just encapsulated it in a Signals class
# File lib/rack-rabbit/signals.rb, line 20
def initialize
  @reader, @writer = IO.pipe
  @queue = []
end

Public Instance Methods

close() click to toggle source
# File lib/rack-rabbit/signals.rb, line 25
def close
  @reader.close
  @writer.close
  @reader = @writer = nil
end
closed?() click to toggle source
# File lib/rack-rabbit/signals.rb, line 31
def closed?
  @reader.nil?
end
pop(options = {}) click to toggle source
# File lib/rack-rabbit/signals.rb, line 41
def pop(options = {})
  raise RuntimeError, "closed" if closed?
  if @queue.empty? && (:timeout == hibernate(options[:timeout]))
    :timeout
  else
    @queue.shift
  end
end
push(item) click to toggle source
# File lib/rack-rabbit/signals.rb, line 35
def push(item)
  raise RuntimeError, "closed" if closed?
  @queue << item
  awaken
end

Private Instance Methods

awaken() click to toggle source
# File lib/rack-rabbit/signals.rb, line 52
def awaken
  @writer.write '.'
end
hibernate(seconds = nil) click to toggle source
# File lib/rack-rabbit/signals.rb, line 56
def hibernate(seconds = nil)
  return :timeout unless IO.select([@reader], nil, nil, seconds)
  @reader.readchar 
end