god 0.4.3 → 0.5.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 +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
|