god 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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