add info to degrading lambda, tested before and after behaviors
[god.git] / lib / god / watch.rb
blobb19b61b8ed173d53828cb798cd884ddb735d4e80
1 require 'etc'
2 require 'forwardable'
4 module God
5   
6   class Watch < Task
7     VALID_STATES = [:init, :up, :start, :restart]
8     INITIAL_STATE = :init
9     
10     # config
11     attr_accessor :grace, :start_grace, :stop_grace, :restart_grace
12     
13     extend Forwardable
14     def_delegators :@process, :name, :uid, :gid, :start, :stop, :restart,
15                               :name=, :uid=, :gid=, :start=, :stop=, :restart=,
16                               :pid_file, :pid_file=, :log, :log=, :alive?    
17     # 
18     def initialize
19       super
20       
21       @process = God::Process.new
22       
23       # valid states
24       self.valid_states = VALID_STATES
25       self.initial_state = INITIAL_STATE
26       
27       # no grace period by default
28       self.grace = self.start_grace = self.stop_grace = self.restart_grace = 0
29     end
30     
31     def valid?
32       super && @process.valid?
33     end
34     
35     ###########################################################################
36     #
37     # Behavior
38     #
39     ###########################################################################
40     
41     def behavior(kind)
42       # create the behavior
43       begin
44         b = Behavior.generate(kind, self)
45       rescue NoSuchBehaviorError => e
46         abort e.message
47       end
48       
49       # send to block so config can set attributes
50       yield(b) if block_given?
51       
52       # abort if the Behavior is invalid, the Behavior will have printed
53       # out its own error messages by now
54       abort unless b.valid?
55       
56       self.behaviors << b
57     end
58     
59     ###########################################################################
60     #
61     # Simple mode
62     #
63     ###########################################################################
64     
65     def start_if
66       self.transition(:up, :start) do |on|
67         yield(on)
68       end
69     end
70     
71     def restart_if
72       self.transition(:up, :restart) do |on|
73         yield(on)
74       end
75     end
76     
77     ###########################################################################
78     #
79     # Lifecycle
80     #
81     ###########################################################################
82     
83     # Enable monitoring
84     def monitor
85       # start monitoring at the first available of the init or up states
86       if !self.metrics[:init].empty?
87         self.move(:init)
88       else
89         self.move(:up)
90       end
91     end
92     
93     ###########################################################################
94     #
95     # Actions
96     #
97     ###########################################################################
98     
99     def action(a, c = nil)
100       case a
101       when :start
102         call_action(c, :start)
103         sleep(self.start_grace + self.grace)
104       when :restart
105         if self.restart
106           call_action(c, :restart)
107         else
108           action(:stop, c)
109           action(:start, c)
110         end
111         sleep(self.restart_grace + self.grace)
112       when :stop
113         call_action(c, :stop)
114         sleep(self.stop_grace + self.grace)
115       end
116     end
117     
118     def call_action(condition, action)
119       # before
120       before_items = self.behaviors
121       before_items += [condition] if condition
122       before_items.each do |b|
123         info = b.send("before_#{action}")
124         if info
125           msg = "#{self.name} before_#{action}: #{info} (#{b.base_name})"
126           Syslog.debug(msg)
127           LOG.log(self, :info, msg)
128         end
129       end
130       
131       # log
132       if self.send(action)
133         msg = "#{self.name} #{action}: #{self.send(action).to_s}"
134         Syslog.debug(msg)
135         LOG.log(self, :info, msg)
136       end
137       
138       @process.call_action(action)
139       
140       # after
141       after_items = self.behaviors
142       after_items += [condition] if condition
143       after_items.each do |b|
144         info = b.send("after_#{action}")
145         if info
146           msg = "#{self.name} after_#{action}: #{info} (#{b.base_name})"
147           Syslog.debug(msg)
148           LOG.log(self, :info, msg)
149         end
150       end
151     end
152     
153     ###########################################################################
154     #
155     # Registration
156     #
157     ###########################################################################
158     
159     def register!
160       God.registry.add(@process)
161     end
162     
163     def unregister!
164       God.registry.remove(@process)
165     end
166   end
167