Class: Flamingo::Daemon::Flamingod

Inherits:
Object
  • Object
show all
Includes:
TrapKeeper
Defined in:
lib/flamingo/daemon/flamingod.rb

Overview

Flamingod is the main overseer of the Flamingo flock.

Starts three sets of children:

  • A wader process: initiates stream request, pushes each response into the queue

  • A Sinatra server: lightweight responder to create and manage subscriptions

  • A set of dispatchers: worker processes that handle each stream response.

You can control the flamingod with the following signals:

  • TERM and INT will kill the flamingod parent process, and signal each child with TERM

  • USR1 will restart the wader gracefully.

Instance Method Summary collapse

Methods included from TrapKeeper

trap

Instance Method Details

#childrenObject



90
91
92
# File 'lib/flamingo/daemon/flamingod.rb', line 90

def children
  ([@wader,@web_server] + @dispatchers).compact
end

#clear_process_meta_dataObject



161
162
163
164
165
166
167
# File 'lib/flamingo/daemon/flamingod.rb', line 161

def 
  meta = Flamingo.meta
  meta.delete(:start_time)
  meta.delete(:host)
  meta.delete(:pid)
  meta[:running] = false
end

#exit_signaled=(val) ⇒ Object



27
28
29
30
# File 'lib/flamingo/daemon/flamingod.rb', line 27

def exit_signaled=(val)
  Flamingo.logger.info "Exit signal set to #{val}"
  @exit_signaled = val
end

#exit_signaled?Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/flamingo/daemon/flamingod.rb', line 23

def exit_signaled?
  @exit_signaled
end

#handle_wader_exit(status) ⇒ Object



124
125
126
127
128
129
130
131
132
133
# File 'lib/flamingo/daemon/flamingod.rb', line 124

def handle_wader_exit(status)
  if WaderProcess.fatal_exit?(status)
    Flamingo.logger.error "Wader exited with status "+
      "#{status.exitstatus} and cannot be automatically restarted"
    $stderr.write("Wader exited with fatal error. Check the the log.")
    terminate!
  else
    @wader = start_new_wader
  end
end

#restart_waderObject



60
61
62
63
64
65
66
67
68
# File 'lib/flamingo/daemon/flamingod.rb', line 60

def restart_wader
  if @wader
    Flamingo.logger.info "Flamingod restarting wader pid=#{@wader.pid} with SIGINT"
    @wader.kill("INT")
  else
    Flamingo.logger.info "Wader is not started. Attempting to start new wader."
    @wader = start_new_wader
  end
end

#runObject



169
170
171
172
173
174
175
176
177
# File 'lib/flamingo/daemon/flamingod.rb', line 169

def run
  $0 = 'flamingod'
  Flamingo.logger.info "Flamingod version: #{Flamingo::VERSION}"
  
  trap_signals
  start_children
  wait_on_children
  
end

#run_as_daemonObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/flamingo/daemon/flamingod.rb', line 135

def run_as_daemon
  pid_file = PidFile.new
  if pid_file.running?
    raise "flamingod process #{pid_file.read} appears to be running"
  end
  pid = fork do
    pid_file.write(Process.pid)
    [$stdout,$stdin,$stderr].each do |io|
      io.reopen '/dev/null' rescue nil
    end
    run
    
    pid_file.delete
  end
  Process.detach(pid)
  pid
end

#set_process_meta_dataObject



153
154
155
156
157
158
159
# File 'lib/flamingo/daemon/flamingod.rb', line 153

def 
  meta = Flamingo.meta
  meta[:start_time] = Time.now.utc.to_i
  meta[:host] = `hostname`.chomp rescue nil
  meta[:pid] = Process.pid
  meta[:running] = true
end

#signal_children(sig) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/flamingo/daemon/flamingod.rb', line 70

def signal_children(sig)
  pids = (children.map {|c| c.pid}).join(",")
  Flamingo.logger.info "Flamingod sending SIG#{sig} to pids=#{pids}"
  children.each do |child|
    if child.running?
      begin
        child.signal(sig)
      rescue => e
        Flamingo.logger.info "Failure sending SIG#{sig} to child #{child.pid}: #{e}"
      end
    end
  end
end

#start_childrenObject



94
95
96
97
98
99
# File 'lib/flamingo/daemon/flamingod.rb', line 94

def start_children
  Flamingo.logger.info "Flamingod starting children"
  @wader = start_new_wader
  @dispatchers = [start_new_dispatcher]
  @web_server = start_new_web_server
end

#start_new_dispatcherObject



39
40
41
42
43
44
# File 'lib/flamingo/daemon/flamingod.rb', line 39

def start_new_dispatcher
  Flamingo.logger.info "Flamingod starting new dispatcher"
  dispatcher = DispatcherProcess.new
  dispatcher.start
  dispatcher
end

#start_new_waderObject



32
33
34
35
36
37
# File 'lib/flamingo/daemon/flamingod.rb', line 32

def start_new_wader
  Flamingo.logger.info "Flamingod starting new wader"
  wader = WaderProcess.new
  wader.start
  wader
end

#start_new_web_serverObject



46
47
48
49
50
51
# File 'lib/flamingo/daemon/flamingod.rb', line 46

def start_new_web_server
  Flamingo.logger.info "Flamingod starting new web server"
  ws = WebServerProcess.new
  ws.start
  ws
end

#terminate!Object



84
85
86
87
88
# File 'lib/flamingo/daemon/flamingod.rb', line 84

def terminate!
  Flamingo.logger.info "Flamingod terminating"
  self.exit_signaled = true
  signal_children("INT")
end

#trap_signalsObject



53
54
55
56
57
58
# File 'lib/flamingo/daemon/flamingod.rb', line 53

def trap_signals
  trap("KILL") { terminate! }
  trap("TERM") { terminate! }
  trap("INT")  { terminate! }
  trap("USR1") { restart_wader }
end

#wait_on_childrenObject

Unless signaled externally, waits in an endless loop. If any child process terminates, it restarts that process. TODO Needs intelligent behavior so we don’t get endless loops



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/flamingo/daemon/flamingod.rb', line 105

def wait_on_children()
  until exit_signaled?
    child_pid = Process.wait(-1)
    child_status = $?
    unless exit_signaled?
      if @wader && @wader.pid == child_pid
        handle_wader_exit(child_status)
      elsif @web_server.pid == child_pid
        @web_server = start_new_web_server
      elsif (to_delete = @dispatchers.find{|d| d.pid == child_pid})
        @dispatchers.delete(to_delete)
        @dispatchers << start_new_dispatcher
      else
        Flamingo.logger.info "Received exit from unknown child #{child_pid}"
      end
    end
  end
end