1 $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
13 require 'god/system/process'
14 require 'god/dependency_graph'
15 require 'god/timeline'
17 require 'god/behavior'
18 require 'god/behaviors/clean_pid_file'
19 require 'god/behaviors/notify_when_flapping'
21 require 'god/condition'
22 require 'god/conditions/process_running'
23 require 'god/conditions/process_exits'
24 require 'god/conditions/tries'
25 require 'god/conditions/memory_usage'
26 require 'god/conditions/cpu_usage'
27 require 'god/conditions/always'
28 require 'god/conditions/lambda'
29 require 'god/conditions/degrading_lambda'
31 require 'god/reporter'
39 require 'god/event_handler'
40 require 'god/registry'
45 $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext god])
53 God::EventHandler.load
56 # Override abort to exit without executing the at_exit hook
68 LOG_BUFFER_SIZE_DEFAULT = 100
69 PID_FILE_DIRECTORY_DEFAULT = '/var/run/god'
70 DRB_PORT_DEFAULT = 17165
71 DRB_ALLOW_DEFAULT = ['127.0.0.1']
82 attr_accessor :inited,
92 abort "God.init must be called before any Watches"
98 def self.internal_init
100 return if self.inited
105 self.pending_watches = []
108 self.log_buffer_size = LOG_BUFFER_SIZE_DEFAULT
109 self.pid_file_directory = PID_FILE_DIRECTORY_DEFAULT
110 self.port = DRB_PORT_DEFAULT
111 self.allow = DRB_ALLOW_DEFAULT
113 # yield to the config file
114 yield self if block_given?
116 # init has been executed
123 # Instantiate a new, empty Watch object and pass it to the mandatory
124 # block. The attributes of the watch will be set by the configuration
132 # if running, completely remove the watch (if necessary) to
133 # prepare for the reload
134 existing_watch = self.watches[w.name]
135 if self.running && existing_watch
136 self.unwatch(existing_watch)
139 # ensure the new watch has a unique name
140 if self.watches[w.name] || self.groups[w.name]
141 abort "Watch name '#{w.name}' already used for a Watch or Group"
144 # ensure watch is internally valid
145 w.valid? || abort("Watch '#{w.name}' is not valid (see above)")
147 # add to list of watches
148 self.watches[w.name] = w
150 # add to pending watches
151 self.pending_watches << w
153 # add to group if specified
155 # ensure group name hasn't been used for a watch already
156 if self.watches[w.group]
157 abort "Group name '#{w.group}' already used for a Watch"
160 self.groups[w.group] ||= []
161 self.groups[w.group] << w
168 def self.unwatch(watch)
175 # remove from watches
176 self.watches.delete(watch.name)
180 self.groups[watch.group].delete(watch)
184 def self.control(name, command)
185 # get the list of watches
186 watches = Array(self.watches[name] || self.groups[name])
192 when "start", "monitor"
193 watches.each { |w| jobs << Thread.new { w.monitor } }
195 watches.each { |w| jobs << Thread.new { w.move(:restart) } }
197 watches.each { |w| jobs << Thread.new { w.unmonitor.action(:stop) } }
199 watches.each { |w| jobs << Thread.new { w.unmonitor } }
201 raise InvalidCommandError.new
204 jobs.each { |j| j.join }
210 self.watches.sort.each do |name, w|
212 w.unmonitor if w.state
213 w.action(:stop) if w.alive?
218 return true unless self.watches.map { |name, w| w.alive? }.any?
231 self.watches.map do |name, w|
232 status = w.state || :unmonitored
233 info[name] = {:state => status}
238 def self.running_log(watch_name, since)
239 unless self.watches[watch_name]
240 raise NoSuchWatchError.new
243 LOG.watch_log_since(watch_name, since)
246 def self.running_load(code)
248 self.pending_watches.each { |w| w.monitor if w.autostart? }
249 watches = self.pending_watches.dup
250 self.pending_watches.clear
255 Dir[glob].each do |f|
262 unless test(?d, self.pid_file_directory)
264 FileUtils.mkdir_p(self.pid_file_directory)
265 rescue Errno::EACCES => e
266 abort "Failed to create pid file directory: #{e.message}"
272 unless test(?w, self.pid_file_directory)
273 abort "The pid file directory (#{self.pid_file_directory}) is not writable by #{Etc.getlogin}"
283 self.server = Server.new(self.host, self.port, self.allow)
285 # start event handler system
286 EventHandler.start if EventHandler.loaded?
288 # start the timer system
291 # start monitoring any watches set to autostart
292 self.watches.values.each { |w| w.monitor if w.autostart? }
294 # clear pending watches
295 self.pending_watches.clear
300 # join the timer thread so we don't exit