Class: Trident::SignalHandler

Inherits:
Object
  • Object
show all
Includes:
GemLogger::LoggerSupport
Defined in:
lib/trident/signal_handler.rb

Constant Summary collapse

CHUNK_SIZE =
(16 * 1024)
SIGNAL_QUEUE_MAX_SIZE =
5
MSG_STOP =
'STOP'

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(signal_mappings, target) ⇒ SignalHandler

Returns a new instance of SignalHandler.



45
46
47
48
49
50
51
52
# File 'lib/trident/signal_handler.rb', line 45

def initialize(signal_mappings, target)
  @target = target
  @signal_queue = []
  @self_pipe = []
  @original_signal_handlers = {}
  @main_loop = nil
  self.signal_mappings = signal_mappings
end

Class Attribute Details

.instanceObject

Returns the value of attribute instance.



13
14
15
# File 'lib/trident/signal_handler.rb', line 13

def instance
  @instance
end

Instance Attribute Details

#original_signal_handlersObject (readonly)

Returns the value of attribute original_signal_handlers.



43
44
45
# File 'lib/trident/signal_handler.rb', line 43

def original_signal_handlers
  @original_signal_handlers
end

#self_pipeObject (readonly)

Returns the value of attribute self_pipe.



43
44
45
# File 'lib/trident/signal_handler.rb', line 43

def self_pipe
  @self_pipe
end

#signal_mappingsObject

Returns the value of attribute signal_mappings.



43
44
45
# File 'lib/trident/signal_handler.rb', line 43

def signal_mappings
  @signal_mappings
end

#signal_queueObject (readonly)

Returns the value of attribute signal_queue.



43
44
45
# File 'lib/trident/signal_handler.rb', line 43

def signal_queue
  @signal_queue
end

#targetObject (readonly)

Returns the value of attribute target.



43
44
45
# File 'lib/trident/signal_handler.rb', line 43

def target
  @target
end

Class Method Details

.joinObject



29
30
31
32
33
# File 'lib/trident/signal_handler.rb', line 29

def join
  raise "No signal handler started" unless instance
  logger.info "Joining on signal handler"
  instance.join
end

.reset_for_forkObject



35
36
37
38
39
# File 'lib/trident/signal_handler.rb', line 35

def reset_for_fork
  raise "No signal handler started" unless instance
  instance.reset_for_fork
  self.instance = nil
end

.start(signal_mappings, target) ⇒ Object



15
16
17
18
19
20
# File 'lib/trident/signal_handler.rb', line 15

def start(signal_mappings, target)
  raise "Already started, call stop if restart needed" if instance
  logger.info "Starting signal handler"
  self.instance = new(signal_mappings, target)
  instance.start
end

.stopObject



22
23
24
25
26
27
# File 'lib/trident/signal_handler.rb', line 22

def stop
  raise "No signal handler started" unless instance
  logger.info "Stopping signal handler"
  instance.stop
  self.instance = nil
end

Instance Method Details

#joinObject



79
80
81
# File 'lib/trident/signal_handler.rb', line 79

def join
  @main_loop.join
end

#reset_for_forkObject



83
84
85
86
# File 'lib/trident/signal_handler.rb', line 83

def reset_for_fork
  @self_pipe = []
  reset_signal_handlers
end

#snoozeObject



99
100
101
102
103
104
105
106
107
108
# File 'lib/trident/signal_handler.rb', line 99

def snooze
  msg = ""
  begin
    ready = IO.select([self_pipe.first], nil, nil, 1) or return
    ready.first && ready.first.first or return
    loop { msg << self_pipe.first.read_nonblock(CHUNK_SIZE) }
  rescue Errno::EAGAIN, Errno::EINTR
  end
  msg
end

#startObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/trident/signal_handler.rb', line 54

def start
  setup_self_pipe
  setup_signal_handlers
  target.start if target.respond_to?(:start)

  @main_loop = Thread.new do
    logger.info "Main loop started"
    loop do
      signal_result = handle_signal_queue
      target.update if target.respond_to?(:update)
      break if signal_result == :break
      logger.debug "Snoozing main loop"
      msg = snooze if signal_queue.empty?
      logger.debug "Main loop awakened: #{msg.inspect}"
      break if msg == MSG_STOP
    end
    logger.info "Main loop exited"
  end
end

#stopObject



74
75
76
77
# File 'lib/trident/signal_handler.rb', line 74

def stop
  reset_signal_handlers
  wakeup(MSG_STOP)
end

#wakeup(msg = '.') ⇒ Object



88
89
90
91
92
93
94
95
96
97
# File 'lib/trident/signal_handler.rb', line 88

def wakeup(msg='.')
  begin
    # mutexes (and thus logging) not allowed within a trap context
    # puts "Waking main loop"
    self_pipe.last.write_nonblock(msg) # wakeup master process from select
  rescue Errno::EAGAIN, Errno::EINTR
    # pipe is full, master should wake up anyways
    retry
  end
end