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.
Files changed (61) hide show
  1. data/History.txt +43 -7
  2. data/Manifest.txt +20 -4
  3. data/Rakefile +1 -1
  4. data/bin/god +263 -195
  5. data/examples/events.god +66 -34
  6. data/examples/gravatar.god +25 -12
  7. data/init/god +42 -0
  8. data/lib/god/behavior.rb +9 -29
  9. data/lib/god/behaviors/clean_pid_file.rb +6 -2
  10. data/lib/god/behaviors/notify_when_flapping.rb +4 -4
  11. data/lib/god/condition.rb +48 -6
  12. data/lib/god/conditions/always.rb +5 -1
  13. data/lib/god/conditions/cpu_usage.rb +13 -5
  14. data/lib/god/conditions/degrading_lambda.rb +8 -3
  15. data/lib/god/conditions/flapping.rb +97 -0
  16. data/lib/god/conditions/http_response_code.rb +97 -0
  17. data/lib/god/conditions/lambda.rb +8 -2
  18. data/lib/god/conditions/memory_usage.rb +13 -5
  19. data/lib/god/conditions/process_exits.rb +11 -3
  20. data/lib/god/conditions/process_running.rb +22 -4
  21. data/lib/god/conditions/tries.rb +16 -5
  22. data/lib/god/configurable.rb +54 -0
  23. data/lib/god/contact.rb +106 -0
  24. data/lib/god/contacts/email.rb +73 -0
  25. data/lib/god/errors.rb +3 -0
  26. data/lib/god/hub.rb +138 -33
  27. data/lib/god/logger.rb +21 -4
  28. data/lib/god/metric.rb +3 -4
  29. data/lib/god/process.rb +93 -49
  30. data/lib/god/socket.rb +60 -0
  31. data/lib/god/task.rb +233 -0
  32. data/lib/god/trigger.rb +43 -0
  33. data/lib/god/watch.rb +48 -114
  34. data/lib/god.rb +216 -63
  35. data/test/configs/child_events/child_events.god +20 -1
  36. data/test/configs/child_polls/child_polls.god +26 -6
  37. data/test/configs/child_polls/simple_server.rb +10 -1
  38. data/test/configs/contact/contact.god +74 -0
  39. data/test/configs/contact/simple_server.rb +3 -0
  40. data/test/configs/daemon_events/daemon_events.god +5 -2
  41. data/test/configs/daemon_events/simple_server.rb +2 -0
  42. data/test/configs/daemon_events/simple_server_stop.rb +9 -0
  43. data/test/configs/degrading_lambda/degrading_lambda.god +1 -3
  44. data/test/configs/task/logs/.placeholder +0 -0
  45. data/test/configs/task/task.god +26 -0
  46. data/test/helper.rb +19 -11
  47. data/test/test_conditions_http_response_code.rb +115 -0
  48. data/test/test_conditions_process_running.rb +2 -2
  49. data/test/test_conditions_tries.rb +21 -0
  50. data/test/test_contact.rb +109 -0
  51. data/test/test_god.rb +101 -17
  52. data/test/test_hub.rb +64 -1
  53. data/test/test_process.rb +43 -56
  54. data/test/{test_server.rb → test_socket.rb} +6 -20
  55. data/test/test_task.rb +86 -0
  56. data/test/test_trigger.rb +59 -0
  57. data/test/test_watch.rb +32 -7
  58. metadata +27 -8
  59. data/lib/god/reporter.rb +0 -25
  60. data/lib/god/server.rb +0 -37
  61. 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/reporter'
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
- # Override abort to exit without executing the at_exit hook
57
- def abort(text)
58
- puts text
59
- exit!
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.4.3'
120
+ VERSION = '0.5.0'
65
121
 
66
- LOG = Logger.new
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
- attr_accessor :host,
76
- :port,
77
- :allow,
78
- :log_buffer_size,
79
- :pid_file_directory
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
- def self.init
91
- if self.inited
92
- abort "God.init must be called before any Watches"
93
- end
94
-
95
- self.internal_init
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 = LOG_BUFFER_SIZE_DEFAULT
109
- self.pid_file_directory = PID_FILE_DIRECTORY_DEFAULT
110
- self.port = DRB_PORT_DEFAULT
111
- self.allow = DRB_ALLOW_DEFAULT
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
- w = Watch.new
130
- yield(w)
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[w.name]
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[w.name] || self.groups[w.name]
141
- abort "Watch name '#{w.name}' already used for a Watch or Group"
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
- w.valid? || abort("Watch '#{w.name}' is not valid (see above)")
213
+ t.valid? || abort("Task '#{t.name}' is not valid (see above)")
146
214
 
147
215
  # add to list of watches
148
- self.watches[w.name] = w
216
+ self.watches[t.name] = t
149
217
 
150
218
  # add to pending watches
151
- self.pending_watches << w
219
+ self.pending_watches << t
152
220
 
153
221
  # add to group if specified
154
- if w.group
222
+ if t.group
155
223
  # ensure group name hasn't been used for a watch already
156
- if self.watches[w.group]
157
- abort "Group name '#{w.group}' already used for a Watch"
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[w.group] ||= []
161
- self.groups[w.group] << w
228
+ self.groups[t.group] ||= []
229
+ self.groups[t.group] << t
162
230
  end
163
231
 
164
232
  # register watch
165
- w.register!
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
- status = w.state || :unmonitored
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
- eval(code)
248
- self.pending_watches.each { |w| w.monitor if w.autostart? }
249
- watches = self.pending_watches.dup
250
- self.pending_watches.clear
251
- watches
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 = Server.new(self.host, self.port, self.allow)
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(File.dirname(__FILE__), *%w[simple_server.rb])
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(File.dirname(__FILE__), *%w[simple_server.rb])
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
@@ -1,3 +1,12 @@
1
1
  #! /usr/bin/env ruby
2
2
 
3
- loop { STDOUT.puts('server'); STDOUT.flush; sleep 1 }
3
+ data = ''
4
+
5
+ loop do
6
+ STDOUT.puts('server');
7
+ STDOUT.flush;
8
+
9
+ 100000.times { data << 'x' }
10
+
11
+ sleep 0.1
12
+ 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
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ loop { puts 'server'; sleep 1 }
@@ -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 = '/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'
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,6 +1,8 @@
1
1
  require 'rubygems'
2
2
  require 'daemons'
3
3
 
4
+ puts 'simple server ahoy!'
5
+
4
6
  Daemons.run_proc('daemon-events', {:dir_mode => :system}) do
5
7
  loop { puts 'server'; sleep 1 }
6
8
  end
@@ -0,0 +1,9 @@
1
+ 3.times do
2
+ puts 'waiting'
3
+ sleep 1
4
+ end
5
+
6
+ p ENV
7
+
8
+ command = '/usr/local/bin/ruby ' + File.join(File.dirname(__FILE__), *%w[simple_server.rb]) + ' stop'
9
+ system(command)
@@ -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