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.
- data/History.txt +26 -2
- data/Manifest.txt +19 -5
- data/Rakefile +7 -2
- data/bin/god +131 -11
- data/examples/events.god +52 -0
- data/examples/gravatar.god +29 -35
- data/ext/god/extconf.rb +49 -2
- data/ext/god/kqueue_handler.c +2 -2
- data/ext/god/netlink_handler.c +17 -4
- data/lib/god.rb +127 -25
- data/lib/god/behavior.rb +8 -3
- data/lib/god/behaviors/clean_pid_file.rb +2 -8
- data/lib/god/condition.rb +6 -5
- data/lib/god/conditions/cpu_usage.rb +4 -4
- data/lib/god/conditions/lambda.rb +19 -0
- data/lib/god/conditions/memory_usage.rb +4 -4
- data/lib/god/conditions/process_exits.rb +5 -7
- data/lib/god/conditions/process_running.rb +4 -4
- data/lib/god/errors.rb +3 -0
- data/lib/god/event_handler.rb +28 -3
- data/lib/god/event_handlers/dummy_handler.rb +13 -0
- data/lib/god/event_handlers/kqueue_handler.rb +2 -0
- data/lib/god/event_handlers/netlink_handler.rb +2 -0
- data/lib/god/hub.rb +40 -23
- data/lib/god/metric.rb +4 -4
- data/lib/god/process.rb +105 -0
- data/lib/god/registry.rb +28 -0
- data/lib/god/server.rb +3 -4
- data/lib/god/sugar.rb +47 -0
- data/lib/god/system/process.rb +1 -2
- data/lib/god/timer.rb +13 -6
- data/lib/god/watch.rb +61 -29
- data/test/configs/child_events/child_events.god +25 -0
- data/test/configs/child_events/simple_server.rb +3 -0
- data/test/configs/child_polls/child_polls.god +15 -0
- data/test/configs/child_polls/simple_server.rb +3 -0
- data/test/configs/daemon_events/daemon_events.god +30 -0
- data/test/configs/daemon_events/simple_server.rb +6 -0
- data/test/configs/real.rb +47 -49
- data/test/configs/test.rb +52 -62
- data/test/helper.rb +44 -14
- data/test/test_behavior.rb +10 -2
- data/test/test_condition.rb +19 -3
- data/test/test_conditions_process_running.rb +42 -0
- data/test/test_event_handler.rb +73 -0
- data/test/test_god.rb +206 -9
- data/test/test_handlers_kqueue_handler.rb +12 -0
- data/test/test_hub.rb +157 -0
- data/test/test_metric.rb +30 -2
- data/test/test_process.rb +84 -0
- data/test/test_registry.rb +14 -0
- data/test/test_server.rb +3 -2
- data/test/test_sugar.rb +42 -0
- data/test/test_system_process.rb +1 -1
- data/test/test_timer.rb +8 -1
- data/test/test_watch.rb +137 -2
- metadata +28 -17
- data/examples/local.god +0 -60
- data/ext/god/Makefile +0 -149
- data/lib/god/base.rb +0 -13
- data/lib/god/meddle.rb +0 -38
- data/test/test_meddle.rb +0 -46
data/lib/god/watch.rb
CHANGED
@@ -1,10 +1,23 @@
|
|
1
|
+
require 'etc'
|
2
|
+
require 'forwardable'
|
3
|
+
|
1
4
|
module God
|
2
5
|
|
3
|
-
class Watch
|
6
|
+
class Watch
|
4
7
|
VALID_STATES = [:init, :up, :start, :restart]
|
5
8
|
|
6
9
|
# config
|
7
|
-
attr_accessor :
|
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
|
17
|
-
@
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
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
|
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
|
-
|
152
|
-
|
153
|
-
|
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
|
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
|
-
|
164
|
-
|
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,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,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
|
data/test/configs/real.rb
CHANGED
@@ -4,58 +4,56 @@ end
|
|
4
4
|
|
5
5
|
RAILS_ROOT = "/Users/tom/dev/git/helloworld"
|
6
6
|
|
7
|
-
God.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
data/test/configs/test.rb
CHANGED
@@ -2,74 +2,64 @@ if $0 == __FILE__
|
|
2
2
|
require File.join(File.dirname(__FILE__), *%w[.. .. lib god])
|
3
3
|
end
|
4
4
|
|
5
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|