god 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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