god 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +43 -7
- data/Manifest.txt +20 -4
- data/Rakefile +1 -1
- data/bin/god +263 -195
- data/examples/events.god +66 -34
- data/examples/gravatar.god +25 -12
- data/init/god +42 -0
- data/lib/god/behavior.rb +9 -29
- data/lib/god/behaviors/clean_pid_file.rb +6 -2
- data/lib/god/behaviors/notify_when_flapping.rb +4 -4
- data/lib/god/condition.rb +48 -6
- data/lib/god/conditions/always.rb +5 -1
- data/lib/god/conditions/cpu_usage.rb +13 -5
- data/lib/god/conditions/degrading_lambda.rb +8 -3
- data/lib/god/conditions/flapping.rb +97 -0
- data/lib/god/conditions/http_response_code.rb +97 -0
- data/lib/god/conditions/lambda.rb +8 -2
- data/lib/god/conditions/memory_usage.rb +13 -5
- data/lib/god/conditions/process_exits.rb +11 -3
- data/lib/god/conditions/process_running.rb +22 -4
- data/lib/god/conditions/tries.rb +16 -5
- data/lib/god/configurable.rb +54 -0
- data/lib/god/contact.rb +106 -0
- data/lib/god/contacts/email.rb +73 -0
- data/lib/god/errors.rb +3 -0
- data/lib/god/hub.rb +138 -33
- data/lib/god/logger.rb +21 -4
- data/lib/god/metric.rb +3 -4
- data/lib/god/process.rb +93 -49
- data/lib/god/socket.rb +60 -0
- data/lib/god/task.rb +233 -0
- data/lib/god/trigger.rb +43 -0
- data/lib/god/watch.rb +48 -114
- data/lib/god.rb +216 -63
- data/test/configs/child_events/child_events.god +20 -1
- data/test/configs/child_polls/child_polls.god +26 -6
- data/test/configs/child_polls/simple_server.rb +10 -1
- data/test/configs/contact/contact.god +74 -0
- data/test/configs/contact/simple_server.rb +3 -0
- data/test/configs/daemon_events/daemon_events.god +5 -2
- data/test/configs/daemon_events/simple_server.rb +2 -0
- data/test/configs/daemon_events/simple_server_stop.rb +9 -0
- data/test/configs/degrading_lambda/degrading_lambda.god +1 -3
- data/test/configs/task/logs/.placeholder +0 -0
- data/test/configs/task/task.god +26 -0
- data/test/helper.rb +19 -11
- data/test/test_conditions_http_response_code.rb +115 -0
- data/test/test_conditions_process_running.rb +2 -2
- data/test/test_conditions_tries.rb +21 -0
- data/test/test_contact.rb +109 -0
- data/test/test_god.rb +101 -17
- data/test/test_hub.rb +64 -1
- data/test/test_process.rb +43 -56
- data/test/{test_server.rb → test_socket.rb} +6 -20
- data/test/test_task.rb +86 -0
- data/test/test_trigger.rb +59 -0
- data/test/test_watch.rb +32 -7
- metadata +27 -8
- data/lib/god/reporter.rb +0 -25
- data/lib/god/server.rb +0 -37
- data/test/test_reporter.rb +0 -18
data/lib/god.rb
CHANGED
@@ -13,6 +13,9 @@ require 'god/logger'
|
|
13
13
|
require 'god/system/process'
|
14
14
|
require 'god/dependency_graph'
|
15
15
|
require 'god/timeline'
|
16
|
+
require 'god/configurable'
|
17
|
+
|
18
|
+
require 'god/task'
|
16
19
|
|
17
20
|
require 'god/behavior'
|
18
21
|
require 'god/behaviors/clean_pid_file'
|
@@ -27,15 +30,20 @@ require 'god/conditions/cpu_usage'
|
|
27
30
|
require 'god/conditions/always'
|
28
31
|
require 'god/conditions/lambda'
|
29
32
|
require 'god/conditions/degrading_lambda'
|
33
|
+
require 'god/conditions/flapping'
|
34
|
+
require 'god/conditions/http_response_code'
|
35
|
+
|
36
|
+
require 'god/contact'
|
37
|
+
require 'god/contacts/email'
|
30
38
|
|
31
|
-
require 'god/
|
32
|
-
require 'god/server'
|
39
|
+
require 'god/socket'
|
33
40
|
require 'god/timer'
|
34
41
|
require 'god/hub'
|
35
42
|
|
36
43
|
require 'god/metric'
|
37
44
|
require 'god/watch'
|
38
45
|
|
46
|
+
require 'god/trigger'
|
39
47
|
require 'god/event_handler'
|
40
48
|
require 'god/registry'
|
41
49
|
require 'god/process'
|
@@ -44,56 +52,104 @@ require 'god/sugar'
|
|
44
52
|
|
45
53
|
$:.unshift File.join(File.dirname(__FILE__), *%w[.. ext god])
|
46
54
|
|
55
|
+
LOG = God::Logger.new
|
56
|
+
LOG.datetime_format = "%Y-%m-%d %H:%M:%S "
|
57
|
+
|
58
|
+
# The $run global determines whether god should be started when the
|
59
|
+
# program would normally end. This should be set to true if when god
|
60
|
+
# should be started (e.g. `god -c <config file>`) and false otherwise
|
61
|
+
# (e.g. `god status`)
|
62
|
+
$run ||= nil
|
63
|
+
|
64
|
+
GOD_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
65
|
+
|
47
66
|
begin
|
48
67
|
Syslog.open('god')
|
49
68
|
rescue RuntimeError
|
50
69
|
Syslog.reopen('god')
|
51
70
|
end
|
52
71
|
|
72
|
+
# Return the binding of god's root level
|
73
|
+
def root_binding
|
74
|
+
binding
|
75
|
+
end
|
76
|
+
|
53
77
|
God::EventHandler.load
|
54
78
|
|
55
79
|
module Kernel
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
80
|
+
alias_method :abort_orig, :abort
|
81
|
+
|
82
|
+
def abort(text = nil)
|
83
|
+
$run = false
|
84
|
+
LOG.log(nil, :error, text) if text
|
85
|
+
text ? abort_orig(text) : exit(1)
|
86
|
+
end
|
87
|
+
|
88
|
+
alias_method :exit_orig, :exit
|
89
|
+
|
90
|
+
def exit(code = 0)
|
91
|
+
$run = false
|
92
|
+
exit_orig(code)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Module
|
97
|
+
def safe_attr_accessor(*args)
|
98
|
+
args.each do |arg|
|
99
|
+
define_method((arg.to_s + "=").intern) do |other|
|
100
|
+
if !self.running && self.inited
|
101
|
+
abort "God.#{arg} must be set before any Tasks are defined"
|
102
|
+
end
|
103
|
+
|
104
|
+
if self.running && self.inited
|
105
|
+
LOG.log(nil, :warn, "God.#{arg} can't be set while god is running")
|
106
|
+
return
|
107
|
+
end
|
108
|
+
|
109
|
+
instance_variable_set(('@' + arg.to_s).intern, other)
|
110
|
+
end
|
111
|
+
|
112
|
+
define_method(arg) do
|
113
|
+
instance_variable_get(('@' + arg.to_s).intern)
|
114
|
+
end
|
115
|
+
end
|
60
116
|
end
|
61
117
|
end
|
62
118
|
|
63
119
|
module God
|
64
|
-
VERSION = '0.
|
120
|
+
VERSION = '0.5.0'
|
65
121
|
|
66
|
-
|
67
|
-
|
68
|
-
LOG_BUFFER_SIZE_DEFAULT = 100
|
122
|
+
LOG_BUFFER_SIZE_DEFAULT = 1000
|
69
123
|
PID_FILE_DIRECTORY_DEFAULT = '/var/run/god'
|
70
124
|
DRB_PORT_DEFAULT = 17165
|
71
125
|
DRB_ALLOW_DEFAULT = ['127.0.0.1']
|
72
126
|
|
73
127
|
class << self
|
74
128
|
# user configurable
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
129
|
+
safe_attr_accessor :host,
|
130
|
+
:port,
|
131
|
+
:allow,
|
132
|
+
:log_buffer_size,
|
133
|
+
:pid_file_directory
|
80
134
|
|
81
135
|
# internal
|
82
136
|
attr_accessor :inited,
|
83
137
|
:running,
|
84
138
|
:pending_watches,
|
139
|
+
:pending_watch_states,
|
85
140
|
:server,
|
86
141
|
:watches,
|
87
|
-
:groups
|
142
|
+
:groups,
|
143
|
+
:contacts,
|
144
|
+
:contact_groups
|
88
145
|
end
|
89
146
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
147
|
+
# initialize class instance variables
|
148
|
+
self.host = nil
|
149
|
+
self.port = nil
|
150
|
+
self.allow = nil
|
151
|
+
self.log_buffer_size = nil
|
152
|
+
self.pid_file_directory = nil
|
97
153
|
|
98
154
|
def self.internal_init
|
99
155
|
# only do this once
|
@@ -103,15 +159,16 @@ module God
|
|
103
159
|
self.watches = {}
|
104
160
|
self.groups = {}
|
105
161
|
self.pending_watches = []
|
162
|
+
self.pending_watch_states = {}
|
163
|
+
self.contacts = {}
|
164
|
+
self.contact_groups = {}
|
106
165
|
|
107
166
|
# set defaults
|
108
|
-
self.log_buffer_size
|
109
|
-
self.pid_file_directory
|
110
|
-
self.port
|
111
|
-
self.allow
|
112
|
-
|
113
|
-
# yield to the config file
|
114
|
-
yield self if block_given?
|
167
|
+
self.log_buffer_size ||= LOG_BUFFER_SIZE_DEFAULT
|
168
|
+
self.pid_file_directory ||= PID_FILE_DIRECTORY_DEFAULT
|
169
|
+
self.port ||= DRB_PORT_DEFAULT
|
170
|
+
self.allow ||= DRB_ALLOW_DEFAULT
|
171
|
+
LOG.level = Logger::INFO
|
115
172
|
|
116
173
|
# init has been executed
|
117
174
|
self.inited = true
|
@@ -119,55 +176,73 @@ module God
|
|
119
176
|
# not yet running
|
120
177
|
self.running = false
|
121
178
|
end
|
122
|
-
|
179
|
+
|
123
180
|
# Instantiate a new, empty Watch object and pass it to the mandatory
|
124
181
|
# block. The attributes of the watch will be set by the configuration
|
125
182
|
# file.
|
126
|
-
def self.watch
|
183
|
+
def self.watch(&block)
|
184
|
+
self.task(Watch, &block)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Instantiate a new, empty Task object and pass it to the mandatory
|
188
|
+
# block. The attributes of the task will be set by the configuration
|
189
|
+
# file.
|
190
|
+
def self.task(klass = Task)
|
127
191
|
self.internal_init
|
128
192
|
|
129
|
-
|
130
|
-
yield(
|
193
|
+
t = klass.new
|
194
|
+
yield(t)
|
195
|
+
|
196
|
+
# do the post-configuration
|
197
|
+
t.prepare
|
131
198
|
|
132
199
|
# if running, completely remove the watch (if necessary) to
|
133
200
|
# prepare for the reload
|
134
|
-
existing_watch = self.watches[
|
201
|
+
existing_watch = self.watches[t.name]
|
135
202
|
if self.running && existing_watch
|
203
|
+
self.pending_watch_states[existing_watch.name] = existing_watch.state
|
136
204
|
self.unwatch(existing_watch)
|
137
205
|
end
|
138
206
|
|
139
207
|
# ensure the new watch has a unique name
|
140
|
-
if self.watches[
|
141
|
-
abort "
|
208
|
+
if self.watches[t.name] || self.groups[t.name]
|
209
|
+
abort "Task name '#{t.name}' already used for a Task or Group"
|
142
210
|
end
|
143
211
|
|
144
212
|
# ensure watch is internally valid
|
145
|
-
|
213
|
+
t.valid? || abort("Task '#{t.name}' is not valid (see above)")
|
146
214
|
|
147
215
|
# add to list of watches
|
148
|
-
self.watches[
|
216
|
+
self.watches[t.name] = t
|
149
217
|
|
150
218
|
# add to pending watches
|
151
|
-
self.pending_watches <<
|
219
|
+
self.pending_watches << t
|
152
220
|
|
153
221
|
# add to group if specified
|
154
|
-
if
|
222
|
+
if t.group
|
155
223
|
# ensure group name hasn't been used for a watch already
|
156
|
-
if self.watches[
|
157
|
-
abort "Group name '#{
|
224
|
+
if self.watches[t.group]
|
225
|
+
abort "Group name '#{t.group}' already used for a Task"
|
158
226
|
end
|
159
227
|
|
160
|
-
self.groups[
|
161
|
-
self.groups[
|
228
|
+
self.groups[t.group] ||= []
|
229
|
+
self.groups[t.group] << t
|
162
230
|
end
|
163
231
|
|
164
232
|
# register watch
|
165
|
-
|
233
|
+
t.register!
|
234
|
+
|
235
|
+
# log
|
236
|
+
if self.running && existing_watch
|
237
|
+
LOG.log(t, :info, "#{t.name} Reloaded config")
|
238
|
+
elsif self.running
|
239
|
+
LOG.log(t, :info, "#{t.name} Loaded config")
|
240
|
+
end
|
166
241
|
end
|
167
242
|
|
168
243
|
def self.unwatch(watch)
|
169
244
|
# unmonitor
|
170
|
-
watch.unmonitor
|
245
|
+
watch.unmonitor unless watch.state == :unmonitored
|
171
246
|
|
172
247
|
# unregister
|
173
248
|
watch.unregister!
|
@@ -180,6 +255,61 @@ module God
|
|
180
255
|
self.groups[watch.group].delete(watch)
|
181
256
|
end
|
182
257
|
end
|
258
|
+
|
259
|
+
def self.contact(kind)
|
260
|
+
self.internal_init
|
261
|
+
|
262
|
+
# create the condition
|
263
|
+
begin
|
264
|
+
c = Contact.generate(kind)
|
265
|
+
rescue NoSuchContactError => e
|
266
|
+
abort e.message
|
267
|
+
end
|
268
|
+
|
269
|
+
# send to block so config can set attributes
|
270
|
+
yield(c) if block_given?
|
271
|
+
|
272
|
+
# call prepare on the contact
|
273
|
+
c.prepare
|
274
|
+
|
275
|
+
# remove existing contacts of same name
|
276
|
+
existing_contact = self.contacts[c.name]
|
277
|
+
if self.running && existing_contact
|
278
|
+
self.uncontact(existing_contact)
|
279
|
+
end
|
280
|
+
|
281
|
+
# ensure the new contact has a unique name
|
282
|
+
if self.contacts[c.name] || self.contact_groups[c.name]
|
283
|
+
abort "Contact name '#{c.name}' already used for a Contact or Contact Group"
|
284
|
+
end
|
285
|
+
|
286
|
+
# abort if the Contact is invalid, the Contact will have printed
|
287
|
+
# out its own error messages by now
|
288
|
+
unless Contact.valid?(c) && c.valid?
|
289
|
+
abort "Exiting on invalid contact"
|
290
|
+
end
|
291
|
+
|
292
|
+
# add to list of contacts
|
293
|
+
self.contacts[c.name] = c
|
294
|
+
|
295
|
+
# add to contact group if specified
|
296
|
+
if c.group
|
297
|
+
# ensure group name hasn't been used for a contact already
|
298
|
+
if self.contacts[c.group]
|
299
|
+
abort "Contact Group name '#{c.group}' already used for a Contact"
|
300
|
+
end
|
301
|
+
|
302
|
+
self.contact_groups[c.group] ||= []
|
303
|
+
self.contact_groups[c.group] << c
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def self.uncontact(contact)
|
308
|
+
self.contacts.delete(contact.name)
|
309
|
+
if contact.group
|
310
|
+
self.contact_groups[contact.group].delete(contact)
|
311
|
+
end
|
312
|
+
end
|
183
313
|
|
184
314
|
def self.control(name, command)
|
185
315
|
# get the list of watches
|
@@ -190,26 +320,26 @@ module God
|
|
190
320
|
# do the command
|
191
321
|
case command
|
192
322
|
when "start", "monitor"
|
193
|
-
watches.each { |w| jobs << Thread.new { w.monitor } }
|
323
|
+
watches.each { |w| jobs << Thread.new { w.monitor if w.state != :up } }
|
194
324
|
when "restart"
|
195
325
|
watches.each { |w| jobs << Thread.new { w.move(:restart) } }
|
196
326
|
when "stop"
|
197
|
-
watches.each { |w| jobs << Thread.new { w.unmonitor.action(:stop) } }
|
327
|
+
watches.each { |w| jobs << Thread.new { w.unmonitor.action(:stop) if w.state != :unmonitored } }
|
198
328
|
when "unmonitor"
|
199
|
-
watches.each { |w| jobs << Thread.new { w.unmonitor } }
|
329
|
+
watches.each { |w| jobs << Thread.new { w.unmonitor if w.state != :unmonitored } }
|
200
330
|
else
|
201
331
|
raise InvalidCommandError.new
|
202
332
|
end
|
203
333
|
|
204
334
|
jobs.each { |j| j.join }
|
205
335
|
|
206
|
-
watches
|
336
|
+
watches.map { |x| x.name }
|
207
337
|
end
|
208
338
|
|
209
339
|
def self.stop_all
|
210
340
|
self.watches.sort.each do |name, w|
|
211
341
|
Thread.new do
|
212
|
-
w.unmonitor if w.state
|
342
|
+
w.unmonitor if w.state != :unmonitored
|
213
343
|
w.action(:stop) if w.alive?
|
214
344
|
end
|
215
345
|
end
|
@@ -229,8 +359,7 @@ module God
|
|
229
359
|
def self.status
|
230
360
|
info = {}
|
231
361
|
self.watches.map do |name, w|
|
232
|
-
|
233
|
-
info[name] = {:state => status}
|
362
|
+
info[name] = {:state => w.state}
|
234
363
|
end
|
235
364
|
info
|
236
365
|
end
|
@@ -243,12 +372,36 @@ module God
|
|
243
372
|
LOG.watch_log_since(watch_name, since)
|
244
373
|
end
|
245
374
|
|
246
|
-
def self.running_load(code)
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
375
|
+
def self.running_load(code, filename)
|
376
|
+
errors = ""
|
377
|
+
watches = []
|
378
|
+
|
379
|
+
begin
|
380
|
+
LOG.start_capture
|
381
|
+
|
382
|
+
eval(code, root_binding, filename)
|
383
|
+
self.pending_watches.each do |w|
|
384
|
+
if previous_state = self.pending_watch_states[w.name]
|
385
|
+
w.monitor unless previous_state == :unmonitored
|
386
|
+
else
|
387
|
+
w.monitor if w.autostart?
|
388
|
+
end
|
389
|
+
end
|
390
|
+
watches = self.pending_watches.dup
|
391
|
+
self.pending_watches.clear
|
392
|
+
self.pending_watch_states.clear
|
393
|
+
rescue Exception => e
|
394
|
+
# don't ever let running_load take down god
|
395
|
+
errors << LOG.finish_capture
|
396
|
+
|
397
|
+
unless e.instance_of?(SystemExit)
|
398
|
+
errors << e.message << "\n"
|
399
|
+
errors << e.backtrace.join("\n")
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
names = watches.map { |x| x.name }
|
404
|
+
[names, errors]
|
252
405
|
end
|
253
406
|
|
254
407
|
def self.load(glob)
|
@@ -280,14 +433,14 @@ module God
|
|
280
433
|
self.validater
|
281
434
|
|
282
435
|
# instantiate server
|
283
|
-
self.server =
|
436
|
+
self.server = Socket.new(self.port)
|
284
437
|
|
285
438
|
# start event handler system
|
286
439
|
EventHandler.start if EventHandler.loaded?
|
287
440
|
|
288
441
|
# start the timer system
|
289
442
|
Timer.get
|
290
|
-
|
443
|
+
|
291
444
|
# start monitoring any watches set to autostart
|
292
445
|
self.watches.values.each { |w| w.monitor if w.autostart? }
|
293
446
|
|
@@ -307,5 +460,5 @@ module God
|
|
307
460
|
end
|
308
461
|
|
309
462
|
at_exit do
|
310
|
-
God.at_exit
|
463
|
+
God.at_exit if $run
|
311
464
|
end
|
@@ -1,7 +1,13 @@
|
|
1
|
+
module God
|
2
|
+
module Behaviors
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
1
6
|
God.watch do |w|
|
2
7
|
w.name = "child-events"
|
3
8
|
w.interval = 5.seconds
|
4
|
-
w.start = File.join(
|
9
|
+
w.start = File.join(GOD_ROOT, *%w[test configs child_events simple_server.rb])
|
10
|
+
w.log = File.join(GOD_ROOT, *%w[test configs child_events god.log])
|
5
11
|
|
6
12
|
# determine the state on startup
|
7
13
|
w.transition(:init, { true => :up, false => :start }) do |on|
|
@@ -27,4 +33,17 @@ God.watch do |w|
|
|
27
33
|
w.transition(:up, :start) do |on|
|
28
34
|
on.condition(:process_exits)
|
29
35
|
end
|
36
|
+
|
37
|
+
# lifecycle
|
38
|
+
w.lifecycle do |on|
|
39
|
+
on.condition(:flapping) do |c|
|
40
|
+
c.to_state = [:start, :restart]
|
41
|
+
c.times = 5
|
42
|
+
c.within = 20.seconds
|
43
|
+
c.transition = :unmonitored
|
44
|
+
c.retry_in = 10.seconds
|
45
|
+
c.retry_times = 2
|
46
|
+
c.retry_within = 5.minutes
|
47
|
+
end
|
48
|
+
end
|
30
49
|
end
|
@@ -1,17 +1,37 @@
|
|
1
1
|
God.watch do |w|
|
2
2
|
w.name = 'child-polls'
|
3
|
-
w.start = File.join(
|
4
|
-
# w.stop = ''
|
3
|
+
w.start = File.join(GOD_ROOT, *%w[test configs child_polls simple_server.rb])
|
5
4
|
w.interval = 5
|
6
5
|
w.grace = 2
|
7
|
-
w.uid = 'tom'
|
8
|
-
w.gid = 'tom'
|
9
|
-
w.group = 'test'
|
10
|
-
w.log = File.join(File.dirname(__FILE__), *%w[out.log])
|
11
6
|
|
12
7
|
w.start_if do |start|
|
13
8
|
start.condition(:process_running) do |c|
|
14
9
|
c.running = false
|
15
10
|
end
|
16
11
|
end
|
12
|
+
|
13
|
+
w.restart_if do |restart|
|
14
|
+
restart.condition(:cpu_usage) do |c|
|
15
|
+
c.above = 30.percent
|
16
|
+
c.times = [3, 5]
|
17
|
+
end
|
18
|
+
|
19
|
+
restart.condition(:memory_usage) do |c|
|
20
|
+
c.above = 10.megabytes
|
21
|
+
c.times = [3, 5]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# lifecycle
|
26
|
+
w.lifecycle do |on|
|
27
|
+
on.condition(:flapping) do |c|
|
28
|
+
c.to_state = [:start, :restart]
|
29
|
+
c.times = 3
|
30
|
+
c.within = 60.seconds
|
31
|
+
c.transition = :unmonitored
|
32
|
+
c.retry_in = 10.seconds
|
33
|
+
c.retry_times = 2
|
34
|
+
c.retry_within = 5.minutes
|
35
|
+
end
|
36
|
+
end
|
17
37
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
God::Contacts::Email.message_settings = {:from => 'support@gravatar.com'}
|
2
|
+
|
3
|
+
God::Contacts::Email.server_settings = {
|
4
|
+
:address => "smtp.aa.powerset.com",
|
5
|
+
:port => 25,
|
6
|
+
:domain => "powerset.com"
|
7
|
+
}
|
8
|
+
|
9
|
+
God.contact(:email) do |c|
|
10
|
+
c.name = 'tom'
|
11
|
+
c.email = 'tom@mojombo.com'
|
12
|
+
c.group = 'developers'
|
13
|
+
end
|
14
|
+
|
15
|
+
God.contact(:email) do |c|
|
16
|
+
c.name = 'vanpelt'
|
17
|
+
c.email = 'vanpelt@example.com'
|
18
|
+
c.group = 'developers'
|
19
|
+
end
|
20
|
+
|
21
|
+
God.contact(:email) do |c|
|
22
|
+
c.name = 'kevin'
|
23
|
+
c.email = 'kevin@example.com'
|
24
|
+
c.group = 'platform'
|
25
|
+
end
|
26
|
+
|
27
|
+
God.watch do |w|
|
28
|
+
w.name = "contact"
|
29
|
+
w.interval = 5.seconds
|
30
|
+
w.start = "ruby " + File.join(File.dirname(__FILE__), *%w[simple_server.rb])
|
31
|
+
w.uid = 'tom'
|
32
|
+
w.gid = 'tom'
|
33
|
+
w.log = "/Users/tom/contact.log"
|
34
|
+
|
35
|
+
# determine the state on startup
|
36
|
+
w.transition(:init, { true => :up, false => :start }) do |on|
|
37
|
+
on.condition(:process_running) do |c|
|
38
|
+
c.running = true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# determine when process has finished starting
|
43
|
+
w.transition([:start, :restart], :up) do |on|
|
44
|
+
on.condition(:process_running) do |c|
|
45
|
+
c.running = true
|
46
|
+
end
|
47
|
+
|
48
|
+
# failsafe
|
49
|
+
on.condition(:tries) do |c|
|
50
|
+
c.times = 2
|
51
|
+
c.transition = :start
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# start if process is not running
|
56
|
+
w.transition(:up, :start) do |on|
|
57
|
+
on.condition(:process_exits) do |c|
|
58
|
+
c.notify = {:contacts => ['tom', 'foobar'], :priority => 1, :category => 'product'}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# lifecycle
|
63
|
+
w.lifecycle do |on|
|
64
|
+
on.condition(:flapping) do |c|
|
65
|
+
c.to_state = [:start, :restart]
|
66
|
+
c.times = 5
|
67
|
+
c.within = 20.seconds
|
68
|
+
c.transition = :unmonitored
|
69
|
+
c.retry_in = 10.seconds
|
70
|
+
c.retry_times = 2
|
71
|
+
c.retry_within = 5.minutes
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -1,9 +1,12 @@
|
|
1
1
|
God.watch do |w|
|
2
2
|
w.name = "daemon-events"
|
3
3
|
w.interval = 5.seconds
|
4
|
-
w.start = '
|
5
|
-
w.stop = '
|
4
|
+
w.start = 'ruby ' + File.join(File.dirname(__FILE__), *%w[simple_server.rb]) + ' start'
|
5
|
+
w.stop = 'ruby ' + File.join(File.dirname(__FILE__), *%w[simple_server_stop.rb])
|
6
6
|
w.pid_file = '/var/run/daemon-events.pid'
|
7
|
+
w.log = File.join(File.dirname(__FILE__), 'daemon_events.log')
|
8
|
+
w.uid = 'tom'
|
9
|
+
w.gid = 'tom'
|
7
10
|
|
8
11
|
w.behavior(:clean_pid_file)
|
9
12
|
|
@@ -1,10 +1,8 @@
|
|
1
1
|
God.watch do |w|
|
2
2
|
w.name = 'degrading-lambda'
|
3
|
-
w.start = File.join(File.dirname(__FILE__), *%w[tcp_server.rb])
|
3
|
+
w.start = 'ruby ' + File.join(File.dirname(__FILE__), *%w[tcp_server.rb])
|
4
4
|
w.interval = 5
|
5
5
|
w.grace = 2
|
6
|
-
w.uid = 'kev'
|
7
|
-
w.gid = 'kev'
|
8
6
|
w.group = 'test'
|
9
7
|
|
10
8
|
w.start_if do |start|
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
LOG_DIR = File.join(File.dirname(__FILE__), *%w[logs])
|
2
|
+
|
3
|
+
God.task do |t|
|
4
|
+
t.name = 'task'
|
5
|
+
t.valid_states = [:ok, :clean]
|
6
|
+
t.initial_state = :ok
|
7
|
+
t.interval = 5
|
8
|
+
|
9
|
+
# t.clean = lambda do
|
10
|
+
# Dir[File.join(LOG_DIR, '*.log')].each do |f|
|
11
|
+
# File.delete(f)
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
|
15
|
+
t.clean = "rm #{File.join(LOG_DIR, '*.log')}"
|
16
|
+
|
17
|
+
t.transition(:clean, :ok)
|
18
|
+
|
19
|
+
t.transition(:ok, :clean) do |on|
|
20
|
+
on.condition(:lambda) do |c|
|
21
|
+
c.lambda = lambda do
|
22
|
+
Dir[File.join(LOG_DIR, '*.log')].size > 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|