7 VALID_STATES = [:init, :up, :start, :restart]
10 attr_accessor :state, :interval, :group,
11 :grace, :start_grace, :stop_grace, :restart_grace
14 attr_writer :autostart
15 def autostart?; @autostart; end
18 def_delegators :@process, :name, :uid, :gid, :start, :stop, :restart,
19 :name=, :uid=, :gid=, :start=, :stop=, :restart=,
20 :pid_file, :pid_file=, :log, :log=, :alive?
23 attr_accessor :behaviors, :metrics
31 @process = God::Process.new
33 # initial state is unmonitored
34 self.state = :unmonitored
36 # no grace period by default
37 self.grace = self.start_grace = self.stop_grace = self.restart_grace = 0
39 # the list of behaviors
42 # the list of conditions for each action
43 self.metrics = {nil => [],
51 self.mutex = Mutex.new
58 ###########################################################################
62 ###########################################################################
67 b = Behavior.generate(kind, self)
68 rescue NoSuchBehaviorError => e
72 # send to block so config can set attributes
73 yield(b) if block_given?
75 # abort if the Behavior is invalid, the Behavior will have printed
76 # out its own error messages by now
82 ###########################################################################
86 ###########################################################################
88 # Define a transition handler which consists of a set of conditions
89 def transition(start_states, end_states)
90 # convert end_states into canonical hash form
91 canonical_end_states = canonical_hash_form(end_states)
93 Array(start_states).each do |start_state|
94 # validate start state
95 unless VALID_STATES.include?(start_state)
96 abort "Invalid state :#{start_state}. Must be one of the symbols #{VALID_STATES.map{|x| ":#{x}"}.join(', ')}"
99 # create a new metric to hold the watch, end states, and conditions
100 m = Metric.new(self, canonical_end_states)
102 # let the config file define some conditions on the metric
106 self.metrics[start_state] << m
111 # create a new metric to hold the watch and conditions
114 # let the config file define some conditions on the metric
118 self.metrics[nil] << m
121 ###########################################################################
125 ###########################################################################
128 self.transition(:up, :start) do |on|
134 self.transition(:up, :restart) do |on|
139 ###########################################################################
143 ###########################################################################
147 # start monitoring at the first available of the init or up states
148 if !self.metrics[:init].empty?
157 self.move(:unmonitored)
160 # Move from one state to another
162 from_state = self.state
164 msg = "#{self.name} move '#{from_state}' to '#{to_state}'"
166 LOG.log(self, :info, msg)
168 # cleanup from current state
169 self.metrics[from_state].each { |m| m.disable }
171 if to_state == :unmonitored
172 self.metrics[nil].each { |m| m.disable }
176 self.action(to_state)
179 if [:start, :restart].include?(to_state) && self.metrics[to_state].empty?
184 self.metrics[to_state].each { |m| m.enable }
186 # if no from state, enable lifecycle metric
187 if from_state == :unmonitored
188 self.metrics[nil].each { |m| m.enable }
192 self.state = to_state
195 Trigger.broadcast(:state_change, [from_state, to_state])
201 def action(a, c = nil)
204 msg = "#{self.name} start: #{self.start.to_s}"
206 LOG.log(self, :info, msg)
207 call_action(c, :start)
208 sleep(self.start_grace + self.grace)
211 msg = "#{self.name} restart: #{self.restart.to_s}"
213 LOG.log(self, :info, msg)
214 call_action(c, :restart)
219 sleep(self.restart_grace + self.grace)
222 msg = "#{self.name} stop: #{self.stop.to_s}"
224 LOG.log(self, :info, msg)
226 call_action(c, :stop)
227 sleep(self.stop_grace + self.grace)
231 def call_action(condition, action)
233 before_items = self.behaviors
234 before_items += [condition] if condition
235 before_items.each { |b| b.send("before_#{action}") }
237 @process.call_action(action)
240 after_items = self.behaviors
241 after_items += [condition] if condition
242 after_items.each { |b| b.send("after_#{action}") }
245 def canonical_hash_form(to)
246 to.instance_of?(Symbol) ? {true => to} : to
250 God.registry.add(@process)
254 God.registry.remove(@process)