mojombo-god 0.7.7

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 (108) hide show
  1. data/History.txt +255 -0
  2. data/Manifest.txt +107 -0
  3. data/README.txt +59 -0
  4. data/Rakefile +35 -0
  5. data/bin/god +127 -0
  6. data/examples/events.god +84 -0
  7. data/examples/gravatar.god +54 -0
  8. data/examples/single.god +66 -0
  9. data/ext/god/extconf.rb +55 -0
  10. data/ext/god/kqueue_handler.c +123 -0
  11. data/ext/god/netlink_handler.c +167 -0
  12. data/init/god +42 -0
  13. data/lib/god.rb +644 -0
  14. data/lib/god/behavior.rb +52 -0
  15. data/lib/god/behaviors/clean_pid_file.rb +21 -0
  16. data/lib/god/behaviors/clean_unix_socket.rb +21 -0
  17. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  18. data/lib/god/cli/command.rb +206 -0
  19. data/lib/god/cli/run.rb +177 -0
  20. data/lib/god/cli/version.rb +23 -0
  21. data/lib/god/condition.rb +96 -0
  22. data/lib/god/conditions/always.rb +23 -0
  23. data/lib/god/conditions/complex.rb +86 -0
  24. data/lib/god/conditions/cpu_usage.rb +80 -0
  25. data/lib/god/conditions/degrading_lambda.rb +52 -0
  26. data/lib/god/conditions/disk_usage.rb +27 -0
  27. data/lib/god/conditions/flapping.rb +128 -0
  28. data/lib/god/conditions/http_response_code.rb +168 -0
  29. data/lib/god/conditions/lambda.rb +25 -0
  30. data/lib/god/conditions/memory_usage.rb +82 -0
  31. data/lib/god/conditions/process_exits.rb +72 -0
  32. data/lib/god/conditions/process_running.rb +74 -0
  33. data/lib/god/conditions/tries.rb +44 -0
  34. data/lib/god/configurable.rb +57 -0
  35. data/lib/god/contact.rb +106 -0
  36. data/lib/god/contacts/email.rb +95 -0
  37. data/lib/god/dependency_graph.rb +41 -0
  38. data/lib/god/diagnostics.rb +37 -0
  39. data/lib/god/driver.rb +108 -0
  40. data/lib/god/errors.rb +24 -0
  41. data/lib/god/event_handler.rb +111 -0
  42. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  43. data/lib/god/event_handlers/kqueue_handler.rb +17 -0
  44. data/lib/god/event_handlers/netlink_handler.rb +13 -0
  45. data/lib/god/logger.rb +120 -0
  46. data/lib/god/metric.rb +59 -0
  47. data/lib/god/process.rb +325 -0
  48. data/lib/god/registry.rb +32 -0
  49. data/lib/god/simple_logger.rb +53 -0
  50. data/lib/god/socket.rb +96 -0
  51. data/lib/god/sugar.rb +47 -0
  52. data/lib/god/system/portable_poller.rb +42 -0
  53. data/lib/god/system/process.rb +42 -0
  54. data/lib/god/system/slash_proc_poller.rb +82 -0
  55. data/lib/god/task.rb +487 -0
  56. data/lib/god/timeline.rb +25 -0
  57. data/lib/god/trigger.rb +43 -0
  58. data/lib/god/watch.rb +183 -0
  59. data/test/configs/child_events/child_events.god +44 -0
  60. data/test/configs/child_events/simple_server.rb +3 -0
  61. data/test/configs/child_polls/child_polls.god +37 -0
  62. data/test/configs/child_polls/simple_server.rb +12 -0
  63. data/test/configs/complex/complex.god +59 -0
  64. data/test/configs/complex/simple_server.rb +3 -0
  65. data/test/configs/contact/contact.god +74 -0
  66. data/test/configs/contact/simple_server.rb +3 -0
  67. data/test/configs/daemon_events/daemon_events.god +37 -0
  68. data/test/configs/daemon_events/simple_server.rb +8 -0
  69. data/test/configs/daemon_events/simple_server_stop.rb +11 -0
  70. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  71. data/test/configs/daemon_polls/simple_server.rb +6 -0
  72. data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
  73. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  74. data/test/configs/matias/matias.god +50 -0
  75. data/test/configs/real.rb +59 -0
  76. data/test/configs/running_load/running_load.god +16 -0
  77. data/test/configs/stress/simple_server.rb +3 -0
  78. data/test/configs/stress/stress.god +15 -0
  79. data/test/configs/task/logs/.placeholder +0 -0
  80. data/test/configs/task/task.god +26 -0
  81. data/test/configs/test.rb +61 -0
  82. data/test/helper.rb +151 -0
  83. data/test/suite.rb +6 -0
  84. data/test/test_behavior.rb +21 -0
  85. data/test/test_condition.rb +50 -0
  86. data/test/test_conditions_disk_usage.rb +56 -0
  87. data/test/test_conditions_http_response_code.rb +109 -0
  88. data/test/test_conditions_process_running.rb +44 -0
  89. data/test/test_conditions_tries.rb +67 -0
  90. data/test/test_contact.rb +109 -0
  91. data/test/test_dependency_graph.rb +62 -0
  92. data/test/test_driver.rb +11 -0
  93. data/test/test_event_handler.rb +80 -0
  94. data/test/test_god.rb +598 -0
  95. data/test/test_handlers_kqueue_handler.rb +16 -0
  96. data/test/test_logger.rb +63 -0
  97. data/test/test_metric.rb +72 -0
  98. data/test/test_process.rb +246 -0
  99. data/test/test_registry.rb +15 -0
  100. data/test/test_socket.rb +42 -0
  101. data/test/test_sugar.rb +42 -0
  102. data/test/test_system_portable_poller.rb +17 -0
  103. data/test/test_system_process.rb +30 -0
  104. data/test/test_task.rb +262 -0
  105. data/test/test_timeline.rb +37 -0
  106. data/test/test_trigger.rb +59 -0
  107. data/test/test_watch.rb +279 -0
  108. metadata +186 -0
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ loop { puts 'server'; sleep 1 }
@@ -0,0 +1,37 @@
1
+ God.watch do |w|
2
+ w.name = "daemon-events"
3
+ w.interval = 5.seconds
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
+ 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'
10
+
11
+ w.behavior(:clean_pid_file)
12
+
13
+ # determine the state on startup
14
+ w.transition(:init, { true => :up, false => :start }) do |on|
15
+ on.condition(:process_running) do |c|
16
+ c.running = true
17
+ end
18
+ end
19
+
20
+ # determine when process has finished starting
21
+ w.transition([:start, :restart], :up) do |on|
22
+ on.condition(:process_running) do |c|
23
+ c.running = true
24
+ end
25
+
26
+ # failsafe
27
+ on.condition(:tries) do |c|
28
+ c.times = 2
29
+ c.transition = :start
30
+ end
31
+ end
32
+
33
+ # start if process is not running
34
+ w.transition(:up, :start) do |on|
35
+ on.condition(:process_exits)
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'daemons'
3
+
4
+ puts 'simple server ahoy!'
5
+
6
+ Daemons.run_proc('daemon-events', {:dir_mode => :system}) do
7
+ loop { puts 'server'; sleep 1 }
8
+ end
@@ -0,0 +1,11 @@
1
+ # exit!(2)
2
+
3
+ 3.times do
4
+ puts 'waiting'
5
+ sleep 1
6
+ end
7
+
8
+ p ENV
9
+
10
+ command = '/usr/local/bin/ruby ' + File.join(File.dirname(__FILE__), *%w[simple_server.rb]) + ' stop'
11
+ system(command)
@@ -0,0 +1,17 @@
1
+ God.watch do |w|
2
+ w.name = "daemon-polls"
3
+ w.interval = 5.seconds
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.rb]) + ' stop'
6
+ w.pid_file = '/var/run/daemon-polls.pid'
7
+ w.start_grace = 2.seconds
8
+ w.log = File.join(File.dirname(__FILE__), *%w[out.log])
9
+
10
+ w.behavior(:clean_pid_file)
11
+
12
+ w.start_if do |start|
13
+ start.condition(:process_running) do |c|
14
+ c.running = false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'daemons'
3
+
4
+ Daemons.run_proc('daemon-polls', {:dir_mode => :system}) do
5
+ loop { STDOUT.puts('server'); STDOUT.flush; sleep 1 }
6
+ end
@@ -0,0 +1,31 @@
1
+ God.watch do |w|
2
+ w.name = 'degrading-lambda'
3
+ w.start = 'ruby ' + File.join(File.dirname(__FILE__), *%w[tcp_server.rb])
4
+ w.interval = 5
5
+ w.grace = 2
6
+ w.group = 'test'
7
+
8
+ w.start_if do |start|
9
+ start.condition(:process_running) do |c|
10
+ c.running = false
11
+ end
12
+ end
13
+
14
+ w.restart_if do |restart|
15
+ restart.condition(:degrading_lambda) do |c|
16
+ require 'socket'
17
+ c.lambda = lambda {
18
+ begin
19
+ sock = TCPSocket.open('127.0.0.1', 9090)
20
+ sock.send "2\n", 0
21
+ retval = sock.gets
22
+ puts "Retval is #{retval}"
23
+ sock.close
24
+ retval
25
+ rescue
26
+ false
27
+ end
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ server = TCPServer.new('127.0.0.1', 9090)
5
+ while (session = server.accept)
6
+ puts "Found a session"
7
+ request = session.gets
8
+ puts "Request: #{request}"
9
+ time = request.to_i
10
+ puts "Sleeping for #{time}"
11
+ sleep time
12
+ session.print "Slept for #{time} seconds"
13
+ session.close
14
+ puts "Session closed"
15
+ end
@@ -0,0 +1,50 @@
1
+ $pid_file = "/tmp/matias.pid"
2
+
3
+ God.task do |w|
4
+ w.name = "watcher"
5
+ w.interval = 5.seconds
6
+ w.valid_states = [:init, :up, :down]
7
+ w.initial_state = :init
8
+
9
+ # determine the state on startup
10
+ w.transition(:init, { true => :up, false => :down }) do |on|
11
+ on.condition(:process_running) do |c|
12
+ c.running = true
13
+ c.pid_file = $pid_file
14
+ end
15
+ end
16
+
17
+ # when process is up
18
+ w.transition(:up, :down) do |on|
19
+ # transition to 'start' if process goes down
20
+ on.condition(:process_running) do |c|
21
+ c.running = false
22
+ c.pid_file = $pid_file
23
+ end
24
+
25
+ # send up info
26
+ on.condition(:lambda) do |c|
27
+ c.lambda = lambda do
28
+ puts 'yay I am up'
29
+ false
30
+ end
31
+ end
32
+ end
33
+
34
+ # when process is down
35
+ w.transition(:down, :up) do |on|
36
+ # transition to 'up' if process comes up
37
+ on.condition(:process_running) do |c|
38
+ c.running = true
39
+ c.pid_file = $pid_file
40
+ end
41
+
42
+ # send down info
43
+ on.condition(:lambda) do |c|
44
+ c.lambda = lambda do
45
+ puts 'boo I am down'
46
+ false
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,59 @@
1
+ if $0 == __FILE__
2
+ require File.join(File.dirname(__FILE__), *%w[.. .. lib god])
3
+ end
4
+
5
+ RAILS_ROOT = "/Users/tom/dev/git/helloworld"
6
+
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
26
+ end
27
+ end
28
+
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]
36
+ end
37
+
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]
43
+ end
44
+ 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
@@ -0,0 +1,16 @@
1
+ God.watch do |w|
2
+ w.name = 'running-load'
3
+ w.start = '/Users/tom/dev/god/test/configs/child_polls/simple_server.rb'
4
+ w.stop = ''
5
+ w.interval = 5
6
+ w.grace = 2
7
+ w.uid = 'tom'
8
+ w.gid = 'tom'
9
+ w.group = 'test'
10
+
11
+ w.start_if do |start|
12
+ start.condition(:process_running) do |c|
13
+ c.running = false
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ loop { puts 'server'; sleep 1 }
@@ -0,0 +1,15 @@
1
+ ('01'..'08').each do |i|
2
+ God.watch do |w|
3
+ w.name = "stress-#{i}"
4
+ w.start = "ruby " + File.join(File.dirname(__FILE__), *%w[simple_server.rb])
5
+ w.interval = 0
6
+ w.grace = 2
7
+ w.group = 'test'
8
+
9
+ w.start_if do |start|
10
+ start.condition(:process_running) do |c|
11
+ c.running = false
12
+ end
13
+ end
14
+ end
15
+ end
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
@@ -0,0 +1,61 @@
1
+ ENV['GOD_TEST_RAILS_ROOT'] || abort("Set a rails root for testing in an environment variable called GOD_TEST_RAILS_ROOT")
2
+
3
+ RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
4
+
5
+ port = 5000
6
+
7
+ God.watch do |w|
8
+ w.name = "local-#{port}"
9
+ w.interval = 5.seconds
10
+ w.start = "mongrel_rails start -P ./log/mongrel.pid -c #{RAILS_ROOT} -p #{port} -d"
11
+ w.restart = "mongrel_rails restart -P ./log/mongrel.pid -c #{RAILS_ROOT}"
12
+ w.stop = "mongrel_rails stop -P ./log/mongrel.pid -c #{RAILS_ROOT}"
13
+ w.group = 'mongrels'
14
+ w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
15
+
16
+ # clean pid files before start if necessary
17
+ w.behavior(:clean_pid_file)
18
+
19
+ # determine the state on startup
20
+ w.transition(:init, { true => :up, false => :start }) do |on|
21
+ on.condition(:process_running) do |c|
22
+ c.running = true
23
+ end
24
+ end
25
+
26
+ # determine when process has finished starting
27
+ w.transition([:start, :restart], :up) do |on|
28
+ on.condition(:process_running) do |c|
29
+ c.running = true
30
+ end
31
+ end
32
+
33
+ # start if process is not running
34
+ w.transition(:up, :start) do |on|
35
+ on.condition(:process_exits)
36
+ end
37
+
38
+ # restart if memory or cpu is too high
39
+ w.transition(:up, :restart) do |on|
40
+ on.condition(:memory_usage) do |c|
41
+ c.interval = 1
42
+ c.above = 50.megabytes
43
+ c.times = [3, 5]
44
+ end
45
+
46
+ on.condition(:cpu_usage) do |c|
47
+ c.interval = 1
48
+ c.above = 10.percent
49
+ c.times = [3, 5]
50
+ end
51
+
52
+ on.condition(:http_response_code) do |c|
53
+ c.host = 'localhost'
54
+ c.port = port
55
+ c.path = '/'
56
+ c.code_is_not = 200
57
+ c.timeout = 10.seconds
58
+ c.times = [3, 5]
59
+ end
60
+ end
61
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,151 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. lib god])
2
+ God::EventHandler.load
3
+
4
+ require 'test/unit'
5
+ require 'set'
6
+
7
+ include God
8
+
9
+ if Process.uid != 0
10
+ abort <<-EOF
11
+ \n
12
+ *********************************************************************
13
+ * *
14
+ * You need to run these tests as root *
15
+ * chroot and netlink (linux only) require it *
16
+ * *
17
+ *********************************************************************
18
+ EOF
19
+ end
20
+
21
+ begin
22
+ require 'mocha'
23
+ rescue LoadError
24
+ unless gems ||= false
25
+ require 'rubygems'
26
+ gems = true
27
+ retry
28
+ else
29
+ abort "=> You need the Mocha gem to run these tests."
30
+ end
31
+ end
32
+
33
+ module God
34
+ module Conditions
35
+ class FakeCondition < Condition
36
+ def test
37
+ true
38
+ end
39
+ end
40
+
41
+ class FakePollCondition < PollCondition
42
+ def test
43
+ true
44
+ end
45
+ end
46
+
47
+ class FakeEventCondition < EventCondition
48
+ def register
49
+ end
50
+ def deregister
51
+ end
52
+ end
53
+ end
54
+
55
+ module Behaviors
56
+ class FakeBehavior < Behavior
57
+ def before_start
58
+ 'foo'
59
+ end
60
+ def after_start
61
+ 'bar'
62
+ end
63
+ end
64
+ end
65
+
66
+ module Contacts
67
+ class FakeContact < Contact
68
+ end
69
+
70
+ class InvalidContact
71
+ end
72
+ end
73
+
74
+ def self.reset
75
+ self.watches = nil
76
+ self.groups = nil
77
+ self.server = nil
78
+ self.inited = nil
79
+ self.host = nil
80
+ self.port = nil
81
+ self.pid_file_directory = nil
82
+ self.registry.reset
83
+ end
84
+ end
85
+
86
+ def silence_warnings
87
+ old_verbose, $VERBOSE = $VERBOSE, nil
88
+ yield
89
+ ensure
90
+ $VERBOSE = old_verbose
91
+ end
92
+
93
+ def no_stdout
94
+ old_stdout = $stdout.dup
95
+ $stdout.reopen(File.open((PLATFORM =~ /mswin/ ? "NUL" : "/dev/null"), 'w'))
96
+ yield
97
+ $stdout.reopen(old_stdout)
98
+ end
99
+
100
+ def no_stderr
101
+ old_stderr = $stderr.dup
102
+ $stderr.reopen(File.open((PLATFORM =~ /mswin/ ? "NUL" : "/dev/null"), 'w'))
103
+ yield
104
+ $stderr.reopen(old_stderr)
105
+ end
106
+
107
+ module Kernel
108
+ def abort(text)
109
+ raise SystemExit
110
+ end
111
+ def exit(code)
112
+ raise SystemExit
113
+ end
114
+ end
115
+
116
+ module Test::Unit::Assertions
117
+ def assert_abort
118
+ assert_raise SystemExit do
119
+ yield
120
+ end
121
+ end
122
+ end
123
+
124
+ # This allows you to be a good OOP citizen and honor encapsulation, but
125
+ # still make calls to private methods (for testing) by doing
126
+ #
127
+ # obj.bypass.private_thingie(arg1, arg2)
128
+ #
129
+ # Which is easier on the eye than
130
+ #
131
+ # obj.send(:private_thingie, arg1, arg2)
132
+ #
133
+ class Object
134
+ class Bypass
135
+ instance_methods.each do |m|
136
+ undef_method m unless m =~ /^__/
137
+ end
138
+
139
+ def initialize(ref)
140
+ @ref = ref
141
+ end
142
+
143
+ def method_missing(sym, *args)
144
+ @ref.__send__(sym, *args)
145
+ end
146
+ end
147
+
148
+ def bypass
149
+ Bypass.new(self)
150
+ end
151
+ end