1 $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
12 require 'god/system/process'
13 require 'god/dependency_graph'
14 require 'god/timeline'
16 require 'god/behavior'
17 require 'god/behaviors/clean_pid_file'
18 require 'god/behaviors/notify_when_flapping'
20 require 'god/condition'
21 require 'god/conditions/process_running'
22 require 'god/conditions/process_exits'
23 require 'god/conditions/tries'
24 require 'god/conditions/memory_usage'
25 require 'god/conditions/cpu_usage'
26 require 'god/conditions/always'
27 require 'god/conditions/lambda'
28 require 'god/conditions/degrading_lambda'
30 require 'god/reporter'
38 require 'god/event_handler'
39 require 'god/registry'
44 $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext god])
52 God::EventHandler.load
59 LOG_BUFFER_SIZE_DEFAULT = 100
60 PID_FILE_DIRECTORY_DEFAULT = '/var/run/god'
61 DRB_PORT_DEFAULT = 17165
62 DRB_ALLOW_DEFAULT = ['127.0.0.1']
73 attr_accessor :inited,
83 abort "God.init must be called before any Watches"
89 def self.internal_init
96 self.pending_watches = []
99 self.log_buffer_size = LOG_BUFFER_SIZE_DEFAULT
100 self.pid_file_directory = PID_FILE_DIRECTORY_DEFAULT
101 self.port = DRB_PORT_DEFAULT
102 self.allow = DRB_ALLOW_DEFAULT
104 # yield to the config file
105 yield self if block_given?
107 # init has been executed
114 # Instantiate a new, empty Watch object and pass it to the mandatory
115 # block. The attributes of the watch will be set by the configuration
123 # if running, completely remove the watch (if necessary) to
124 # prepare for the reload
125 existing_watch = self.watches[w.name]
126 if self.running && existing_watch
127 self.unwatch(existing_watch)
130 # ensure the new watch has a unique name
131 if self.watches[w.name] || self.groups[w.name]
132 abort "Watch name '#{w.name}' already used for a Watch or Group"
135 # ensure watch is internally valid
136 w.valid? || abort("Watch '#{w.name}' is not valid (see above)")
138 # add to list of watches
139 self.watches[w.name] = w
141 # add to pending watches
142 self.pending_watches << w
144 # add to group if specified
146 # ensure group name hasn't been used for a watch already
147 if self.watches[w.group]
148 abort "Group name '#{w.group}' already used for a Watch"
151 self.groups[w.group] ||= []
152 self.groups[w.group] << w
159 def self.unwatch(watch)
166 # remove from watches
167 self.watches.delete(watch.name)
171 self.groups[watch.group].delete(watch)
175 def self.control(name, command)
176 # get the list of watches
177 watches = Array(self.watches[name] || self.groups[name])
181 when "start", "monitor"
182 watches.each { |w| w.monitor }
184 watches.each { |w| w.move(:restart) }
186 watches.each { |w| w.unmonitor.action(:stop) }
188 watches.each { |w| w.unmonitor }
190 raise InvalidCommandError.new
197 self.watches.sort.each do |name, w|
199 w.unmonitor if w.state
200 w.action(:stop) if w.alive?
205 return true unless self.watches.map { |name, w| w.alive? }.any?
218 self.watches.map do |name, w|
219 status = w.state || :unmonitored
220 info[name] = {:state => status}
225 def self.running_log(watch_name, since)
226 unless self.watches[watch_name]
227 raise NoSuchWatchError.new
230 LOG.watch_log_since(watch_name, since)
233 def self.running_load(code)
235 self.pending_watches.each { |w| w.monitor if w.autostart? }
236 watches = self.pending_watches.dup
237 self.pending_watches.clear
242 Dir[glob].each do |f|
249 unless test(?d, self.pid_file_directory)
251 FileUtils.mkdir_p(self.pid_file_directory)
252 rescue Errno::EACCES => e
253 abort "Failed to create pid file directory: #{e.message}"
259 unless test(?w, self.pid_file_directory)
260 abort "The pid file directory (#{self.pid_file_directory}) is not writable by #{Etc.getlogin}"
270 self.server = Server.new(self.host, self.port, self.allow)
272 # start event handler system
273 EventHandler.start if EventHandler.loaded?
275 # start the timer system
278 # start monitoring any watches set to autostart
279 self.watches.values.each { |w| w.monitor if w.autostart? }
281 # clear pending watches
282 self.pending_watches.clear
287 # join the timer thread so we don't exit