god 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/History.txt +26 -2
  2. data/Manifest.txt +19 -5
  3. data/Rakefile +7 -2
  4. data/bin/god +131 -11
  5. data/examples/events.god +52 -0
  6. data/examples/gravatar.god +29 -35
  7. data/ext/god/extconf.rb +49 -2
  8. data/ext/god/kqueue_handler.c +2 -2
  9. data/ext/god/netlink_handler.c +17 -4
  10. data/lib/god.rb +127 -25
  11. data/lib/god/behavior.rb +8 -3
  12. data/lib/god/behaviors/clean_pid_file.rb +2 -8
  13. data/lib/god/condition.rb +6 -5
  14. data/lib/god/conditions/cpu_usage.rb +4 -4
  15. data/lib/god/conditions/lambda.rb +19 -0
  16. data/lib/god/conditions/memory_usage.rb +4 -4
  17. data/lib/god/conditions/process_exits.rb +5 -7
  18. data/lib/god/conditions/process_running.rb +4 -4
  19. data/lib/god/errors.rb +3 -0
  20. data/lib/god/event_handler.rb +28 -3
  21. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  22. data/lib/god/event_handlers/kqueue_handler.rb +2 -0
  23. data/lib/god/event_handlers/netlink_handler.rb +2 -0
  24. data/lib/god/hub.rb +40 -23
  25. data/lib/god/metric.rb +4 -4
  26. data/lib/god/process.rb +105 -0
  27. data/lib/god/registry.rb +28 -0
  28. data/lib/god/server.rb +3 -4
  29. data/lib/god/sugar.rb +47 -0
  30. data/lib/god/system/process.rb +1 -2
  31. data/lib/god/timer.rb +13 -6
  32. data/lib/god/watch.rb +61 -29
  33. data/test/configs/child_events/child_events.god +25 -0
  34. data/test/configs/child_events/simple_server.rb +3 -0
  35. data/test/configs/child_polls/child_polls.god +15 -0
  36. data/test/configs/child_polls/simple_server.rb +3 -0
  37. data/test/configs/daemon_events/daemon_events.god +30 -0
  38. data/test/configs/daemon_events/simple_server.rb +6 -0
  39. data/test/configs/real.rb +47 -49
  40. data/test/configs/test.rb +52 -62
  41. data/test/helper.rb +44 -14
  42. data/test/test_behavior.rb +10 -2
  43. data/test/test_condition.rb +19 -3
  44. data/test/test_conditions_process_running.rb +42 -0
  45. data/test/test_event_handler.rb +73 -0
  46. data/test/test_god.rb +206 -9
  47. data/test/test_handlers_kqueue_handler.rb +12 -0
  48. data/test/test_hub.rb +157 -0
  49. data/test/test_metric.rb +30 -2
  50. data/test/test_process.rb +84 -0
  51. data/test/test_registry.rb +14 -0
  52. data/test/test_server.rb +3 -2
  53. data/test/test_sugar.rb +42 -0
  54. data/test/test_system_process.rb +1 -1
  55. data/test/test_timer.rb +8 -1
  56. data/test/test_watch.rb +137 -2
  57. metadata +28 -17
  58. data/examples/local.god +0 -60
  59. data/ext/god/Makefile +0 -149
  60. data/lib/god/base.rb +0 -13
  61. data/lib/god/meddle.rb +0 -38
  62. data/test/test_meddle.rb +0 -46
@@ -1,10 +1,23 @@
1
+ require 'etc'
2
+ require 'forwardable'
3
+
1
4
  module God
2
5
 
3
- class Watch < Base
6
+ class Watch
4
7
  VALID_STATES = [:init, :up, :start, :restart]
5
8
 
6
9
  # config
7
- attr_accessor :name, :state, :start, :stop, :restart, :interval, :grace
10
+ attr_accessor :state, :interval, :group,
11
+ :grace, :start_grace, :stop_grace, :restart_grace
12
+
13
+
14
+ attr_writer :autostart
15
+ def autostart?; @autostart; end
16
+
17
+ extend Forwardable
18
+ def_delegators :@process, :name, :uid, :gid, :start, :stop, :restart,
19
+ :name=, :uid=, :gid=, :start=, :stop=, :restart=,
20
+ :pid_file, :pid_file=
8
21
 
9
22
  # api
10
23
  attr_accessor :behaviors, :metrics
@@ -13,11 +26,12 @@ module God
13
26
  attr_accessor :mutex
14
27
 
15
28
  #
16
- def initialize(meddle)
17
- @meddle = meddle
29
+ def initialize
30
+ @autostart ||= true
31
+ @process = God::Process.new
18
32
 
19
33
  # no grace period by default
20
- self.grace = 0
34
+ self.grace = self.start_grace = self.stop_grace = self.restart_grace = 0
21
35
 
22
36
  # the list of behaviors
23
37
  self.behaviors = []
@@ -35,7 +49,7 @@ module God
35
49
  def behavior(kind)
36
50
  # create the behavior
37
51
  begin
38
- b = Behavior.generate(kind)
52
+ b = Behavior.generate(kind, self)
39
53
  rescue NoSuchBehaviorError => e
40
54
  abort e.message
41
55
  end
@@ -103,7 +117,7 @@ module God
103
117
  #
104
118
  ###########################################################################
105
119
 
106
- # Schedule all poll conditions and register all condition events
120
+ # Enable monitoring
107
121
  def monitor
108
122
  # start monitoring at the first available of the init or up states
109
123
  if !self.metrics[:init].empty?
@@ -113,62 +127,76 @@ module God
113
127
  end
114
128
  end
115
129
 
130
+ # Disable monitoring
131
+ def unmonitor
132
+ self.move(nil)
133
+ end
134
+
116
135
  # Move from one state to another
117
136
  def move(to_state)
118
- puts "move '#{self.state}' to '#{to_state}'"
137
+ msg = "#{self.name} move '#{self.state}' to '#{to_state}'"
138
+ Syslog.debug(msg)
139
+ puts msg
119
140
 
120
141
  # cleanup from current state
121
- if from_state = self.state
142
+ from_state = self.state
143
+ if from_state
122
144
  self.metrics[from_state].each { |m| m.disable }
123
145
  end
124
146
 
125
- # perform action (if available)
147
+ # perform action
126
148
  self.action(to_state)
127
149
 
150
+ # enable simple mode
151
+ if [:start, :restart].include?(to_state) && self.metrics[to_state].empty?
152
+ to_state = :up
153
+ end
154
+
128
155
  # move to new state
129
- self.metrics[to_state].each { |m| m.enable }
156
+ if to_state
157
+ self.metrics[to_state].each { |m| m.enable }
158
+ end
130
159
 
131
160
  # set state
132
161
  self.state = to_state
162
+
163
+ # return self
164
+ self
133
165
  end
134
166
 
135
167
  def action(a, c = nil)
136
168
  case a
137
169
  when :start
138
- puts self.start
139
- call_action(c, :start, self.start)
140
- sleep(self.grace)
170
+ Syslog.debug(self.start.to_s)
171
+ puts self.start.to_s
172
+ call_action(c, :start)
173
+ sleep(self.start_grace + self.grace)
141
174
  when :restart
142
175
  if self.restart
176
+ Syslog.debug(self.restart.to_s)
143
177
  puts self.restart
144
- call_action(c, :restart, self.restart)
178
+ call_action(c, :restart)
145
179
  else
146
180
  action(:stop, c)
147
181
  action(:start, c)
148
182
  end
149
- sleep(self.grace)
183
+ sleep(self.restart_grace + self.grace)
150
184
  when :stop
151
- puts self.stop
152
- call_action(c, :stop, self.stop)
153
- sleep(self.grace)
185
+ Syslog.debug(self.stop.to_s)
186
+ puts self.stop.to_s
187
+ call_action(c, :stop)
188
+ sleep(self.stop_grace + self.grace)
154
189
  end
155
190
  end
156
191
 
157
- def call_action(condition, action, command)
192
+ def call_action(condition, action)
158
193
  # before
159
194
  before_items = self.behaviors
160
195
  before_items += [condition] if condition
161
196
  before_items.each { |b| b.send("before_#{action}") }
162
197
 
163
- # action
164
- if command.kind_of?(String)
165
- # string command
166
- system(command)
167
- else
168
- # lambda command
169
- command.call
170
- end
171
-
198
+ @process.call_action(action)
199
+
172
200
  # after
173
201
  after_items = self.behaviors
174
202
  after_items += [condition] if condition
@@ -178,6 +206,10 @@ module God
178
206
  def canonical_hash_form(to)
179
207
  to.instance_of?(Symbol) ? {true => to} : to
180
208
  end
209
+
210
+ def register!
211
+ God.registry.add(@process)
212
+ end
181
213
  end
182
214
 
183
215
  end
@@ -0,0 +1,25 @@
1
+ God.watch do |w|
2
+ w.name = "child-events"
3
+ w.interval = 5.seconds
4
+ w.start = File.join(File.dirname(__FILE__), *%w[simple_server.rb])
5
+ w.stop = ""
6
+
7
+ # determine the state on startup
8
+ w.transition(:init, { true => :up, false => :start }) do |on|
9
+ on.condition(:process_running) do |c|
10
+ c.running = true
11
+ end
12
+ end
13
+
14
+ # determine when process has finished starting
15
+ w.transition(:start, :up) do |on|
16
+ on.condition(:process_running) do |c|
17
+ c.running = true
18
+ end
19
+ end
20
+
21
+ # start if process is not running
22
+ w.transition(:up, :start) do |on|
23
+ on.condition(:process_exits)
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ loop { puts 'server'; sleep 1 }
@@ -0,0 +1,15 @@
1
+ God.watch do |w|
2
+ w.name = 'child-polls'
3
+ w.start = File.join(File.dirname(__FILE__), *%w[simple_server.rb])
4
+ w.stop = ''
5
+ w.interval = 5
6
+ w.grace = 2
7
+ w.uid = 'tom'
8
+ w.gid = 'tom'
9
+
10
+ w.start_if do |start|
11
+ start.condition(:process_running) do |c|
12
+ c.running = false
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ loop { puts 'server'; sleep 1 }
@@ -0,0 +1,30 @@
1
+ God.watch do |w|
2
+ w.name = "daemon-events"
3
+ w.interval = 5.seconds
4
+ w.start = '/usr/local/bin/ruby ' + File.join(File.dirname(__FILE__), *%w[simple_server.rb]) + ' start'
5
+ w.stop = '/usr/local/bin/ruby ' + File.join(File.dirname(__FILE__), *%w[simple_server.rb]) + ' stop'
6
+ w.uid = 'tom'
7
+ w.gid = 'tom'
8
+ w.pid_file = '/var/run/daemon-events.pid'
9
+
10
+ w.behavior(:clean_pid_file)
11
+
12
+ # determine the state on startup
13
+ w.transition(:init, { true => :up, false => :start }) do |on|
14
+ on.condition(:process_running) do |c|
15
+ c.running = true
16
+ end
17
+ end
18
+
19
+ # determine when process has finished starting
20
+ w.transition(:start, :up) do |on|
21
+ on.condition(:process_running) do |c|
22
+ c.running = true
23
+ end
24
+ end
25
+
26
+ # start if process is not running
27
+ w.transition(:up, :start) do |on|
28
+ on.condition(:process_exits)
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'daemons'
3
+
4
+ Daemons.run_proc('daemon-events', {:dir_mode => :system}) do
5
+ loop { puts 'server'; sleep 1 }
6
+ end
@@ -4,58 +4,56 @@ end
4
4
 
5
5
  RAILS_ROOT = "/Users/tom/dev/git/helloworld"
6
6
 
7
- God.meddle do |god|
8
- god.watch do |w|
9
- w.name = "local-3000"
10
- w.interval = 5 # seconds
11
- w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
12
- w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
13
- w.grace = 5
14
-
15
- pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
16
-
17
- # clean pid files before start if necessary
18
- w.behavior(:clean_pid_file) do |b|
19
- b.pid_file = pid_file
7
+ God.watch do |w|
8
+ w.name = "local-3000"
9
+ w.interval = 5 # seconds
10
+ w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -d"
11
+ w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
12
+ w.grace = 5
13
+
14
+ pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
15
+
16
+ # clean pid files before start if necessary
17
+ w.behavior(:clean_pid_file) do |b|
18
+ b.pid_file = pid_file
19
+ end
20
+
21
+ # start if process is not running
22
+ w.start_if do |start|
23
+ start.condition(:process_running) do |c|
24
+ c.running = false
25
+ c.pid_file = pid_file
20
26
  end
27
+ end
21
28
 
22
- # start if process is not running
23
- w.start_if do |start|
24
- start.condition(:process_running) do |c|
25
- c.running = false
26
- c.pid_file = pid_file
27
- end
29
+ # restart if memory or cpu is too high
30
+ w.restart_if do |restart|
31
+ restart.condition(:memory_usage) do |c|
32
+ c.interval = 20
33
+ c.pid_file = pid_file
34
+ c.above = (50 * 1024) # 50mb
35
+ c.times = [3, 5]
28
36
  end
29
37
 
30
- # restart if memory or cpu is too high
31
- w.restart_if do |restart|
32
- restart.condition(:memory_usage) do |c|
33
- c.interval = 20
34
- c.pid_file = pid_file
35
- c.above = (50 * 1024) # 50mb
36
- c.times = [3, 5]
37
- end
38
-
39
- restart.condition(:cpu_usage) do |c|
40
- c.interval = 10
41
- c.pid_file = pid_file
42
- c.above = 10 # percent
43
- c.times = [3, 5]
44
- end
38
+ restart.condition(:cpu_usage) do |c|
39
+ c.interval = 10
40
+ c.pid_file = pid_file
41
+ c.above = 10 # percent
42
+ c.times = [3, 5]
45
43
  end
46
44
  end
47
-
48
- # clear old session files
49
- # god.watch do |w|
50
- # w.name = "local-session-cleanup"
51
- # w.start = lambda do
52
- # Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f|
53
- # File.mtime(f) < Time.now - (7 * 24 * 60 * 60)
54
- # end.each { |f| File.delete(f) }
55
- # end
56
- #
57
- # w.start_if do |start|
58
- # start.condition(:always)
59
- # end
60
- # end
61
- end
45
+ end
46
+
47
+ # clear old session files
48
+ # god.watch do |w|
49
+ # w.name = "local-session-cleanup"
50
+ # w.start = lambda do
51
+ # Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f|
52
+ # File.mtime(f) < Time.now - (7 * 24 * 60 * 60)
53
+ # end.each { |f| File.delete(f) }
54
+ # end
55
+ #
56
+ # w.start_if do |start|
57
+ # start.condition(:always)
58
+ # end
59
+ # end
@@ -2,74 +2,64 @@ if $0 == __FILE__
2
2
  require File.join(File.dirname(__FILE__), *%w[.. .. lib god])
3
3
  end
4
4
 
5
- RAILS_ROOT = "/Users/tom/dev/git/helloworld"
5
+ ENV['GOD_TEST_RAILS_ROOT'] || abort("Set a rails root for testing in an environment variable called GOD_TEST_RAILS_ROOT")
6
6
 
7
- God.meddle do |god|
8
- god.watch do |w|
9
- w.name = "local-3000"
10
- w.interval = 5 # seconds
11
- w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -p 3001 -d"
12
- w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
13
-
14
- pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
15
-
16
- # clean pid files before start if necessary
17
- w.behavior(:clean_pid_file) do |b|
18
- b.pid_file = pid_file
19
- end
20
-
21
- # determine the state on startup
22
- w.transition(:init, { true => :up, false => :start }) do |on|
23
- on.condition(:process_running) do |c|
24
- c.running = true
25
- c.pid_file = pid_file
26
- end
7
+ RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
8
+
9
+ God.init do |g|
10
+ # g.host =
11
+ # g.port = 7777
12
+ # g.pid_file_directory =
13
+ end
14
+
15
+ God.watch do |w|
16
+ w.name = "local-3000"
17
+ w.interval = 5.seconds
18
+ w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -p 3001 -d"
19
+ w.restart = "mongrel_rails restart -P ./log/mongrel.pid -c #{RAILS_ROOT}"
20
+ w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
21
+ w.restart_grace = 5.seconds
22
+ w.stop_grace = 5.seconds
23
+ w.autostart = true
24
+ w.uid = 'tom'
25
+ w.gid = 'tom'
26
+ w.group = 'mongrels'
27
+ w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
28
+
29
+ # clean pid files before start if necessary
30
+ w.behavior(:clean_pid_file)
31
+
32
+ # determine the state on startup
33
+ w.transition(:init, { true => :up, false => :start }) do |on|
34
+ on.condition(:process_running) do |c|
35
+ c.running = true
27
36
  end
28
-
29
- # determine when process has finished starting
30
- w.transition([:start, :restart], :up) do |on|
31
- on.condition(:process_running) do |c|
32
- c.running = true
33
- c.pid_file = pid_file
34
- end
37
+ end
38
+
39
+ # determine when process has finished starting
40
+ w.transition([:start, :restart], :up) do |on|
41
+ on.condition(:process_running) do |c|
42
+ c.running = true
35
43
  end
44
+ end
45
+
46
+ # start if process is not running
47
+ w.transition(:up, :start) do |on|
48
+ on.condition(:process_exits)
49
+ end
36
50
 
37
- # start if process is not running
38
- w.transition(:up, :start) do |on|
39
- on.condition(:process_exits) do |c|
40
- c.pid_file = pid_file
41
- end
51
+ # restart if memory or cpu is too high
52
+ w.transition(:up, :restart) do |on|
53
+ on.condition(:memory_usage) do |c|
54
+ c.interval = 1
55
+ c.above = 50.megabytes
56
+ c.times = [3, 5]
42
57
  end
43
58
 
44
- # restart if memory or cpu is too high
45
- w.transition(:up, :restart) do |on|
46
- on.condition(:memory_usage) do |c|
47
- c.interval = 20
48
- c.pid_file = pid_file
49
- c.above = (50 * 1024) # 50mb
50
- c.times = [3, 5]
51
- end
52
-
53
- on.condition(:cpu_usage) do |c|
54
- c.interval = 10
55
- c.pid_file = pid_file
56
- c.above = 10 # percent
57
- c.times = [3, 5]
58
- end
59
+ on.condition(:cpu_usage) do |c|
60
+ c.interval = 1
61
+ c.above = 10.percent
62
+ c.times = [3, 5]
59
63
  end
60
64
  end
61
-
62
- # clear old session files
63
- # god.watch do |w|
64
- # w.name = "local-session-cleanup"
65
- # w.start = lambda do
66
- # Dir["#{RAILS_ROOT}/tmp/sessions/ruby_sess.*"].select do |f|
67
- # File.mtime(f) < Time.now - (7 * 24 * 60 * 60)
68
- # end.each { |f| File.delete(f) }
69
- # end
70
- #
71
- # w.start_if do |start|
72
- # start.condition(:always)
73
- # end
74
- # end
75
65
  end