From 2513384d3f9b49869954f5e7dfe928f21a3afa89 Mon Sep 17 00:00:00 2001 From: Tom Werner Date: Fri, 26 Oct 2007 18:12:16 -0700 Subject: [PATCH] start work on complex condition --- lib/god.rb | 1 + lib/god/conditions/complex.rb | 86 +++++++++++++++++++++++++++++++++++ test/configs/complex/complex.god | 59 ++++++++++++++++++++++++ test/configs/complex/simple_server.rb | 3 ++ 4 files changed, 149 insertions(+) create mode 100644 lib/god/conditions/complex.rb create mode 100644 test/configs/complex/complex.god create mode 100755 test/configs/complex/simple_server.rb diff --git a/lib/god.rb b/lib/god.rb index 59421ef..dbddbc2 100644 --- a/lib/god.rb +++ b/lib/god.rb @@ -33,6 +33,7 @@ require 'god/conditions/degrading_lambda' require 'god/conditions/flapping' require 'god/conditions/http_response_code' require 'god/conditions/disk_usage' +require 'god/conditions/complex' require 'god/contact' require 'god/contacts/email' diff --git a/lib/god/conditions/complex.rb b/lib/god/conditions/complex.rb new file mode 100644 index 0000000..50dd8ed --- /dev/null +++ b/lib/god/conditions/complex.rb @@ -0,0 +1,86 @@ +module God + module Conditions + + class Complex < PollCondition + AND = 0x1 + OR = 0x2 + NOT = 0x4 + + def initialize() + super + + @oper_stack = [] + @op_stack = [] + + @this = nil + end + + def valid? + @oper_stack.inject(true) { |acc, oper| acc & oper.valid? } + end + + def prepare + @oper_stack.each { |oper| oper.prepare } + end + + def new_oper(kind, op) + oper = Condition.generate(kind, self.watch) + @oper_stack.push(oper) + @op_stack.push(op) + oper + end + + def this(kind) + @this = Condition.generate(kind, self.watch) + yield @this if block_given? + end + + def and(kind) + oper = new_oper(kind, 0x1) + yield oper if block_given? + end + + def and_not(kind) + oper = new_oper(kind, 0x5) + yield oper if block_given? + end + + def or(kind) + oper = new_oper(kind, 0x2) + yield oper if block_given? + end + + def or_not(kind) + oper = new_oper(kind, 0x6) + yield oper if block_given? + end + + def test + if @this.nil? + # Although this() makes sense semantically and therefore + # encourages easy-to-read conditions, being able to omit it + # allows for more DRY code in some cases, so we deal with a + # nil @this here by initially setting res to true or false, + # depending on whether the first operator used is AND or OR + # respectively. + if 0 < @op_stack[0] & AND + res = true + else + res = false + end + else + res = @this.test + end + + @op_stack.each do |op| + cond = @oper_stack.shift + eval "res " + ((0 < op & AND) ? "&&" : "||") + "= " + ((0 < op & NOT) ? "!" : "") + "cond.test" + @oper_stack.push cond + end + + res + end + end + + end +end \ No newline at end of file diff --git a/test/configs/complex/complex.god b/test/configs/complex/complex.god new file mode 100644 index 0000000..d03d635 --- /dev/null +++ b/test/configs/complex/complex.god @@ -0,0 +1,59 @@ +God.watch do |w| + w.name = "complex" + w.interval = 5.seconds + w.start = File.join(GOD_ROOT, *%w[test configs complex simple_server.rb]) + # w.log = File.join(GOD_ROOT, *%w[test configs child_events god.log]) + + # determine the state on startup + w.transition(:init, { true => :up, false => :start }) do |on| + on.condition(:process_running) do |c| + c.running = true + end + end + + # determine when process has finished starting + w.transition([:start, :restart], :up) do |on| + on.condition(:process_running) do |c| + c.running = true + end + + # failsafe + on.condition(:tries) do |c| + c.times = 2 + c.transition = :start + end + end + + # start if process is not running + w.transition(:up, :start) do |on| + on.condition(:process_exits) + end + + # restart if process is misbehaving + w.transition(:up, :restart) do |on| + on.condition(:complex) do |cc| + cc.and(:cpu_usage) do |c| + c.above = 0.percent + c.times = 1 + end + + cc.and(:memory_usage) do |c| + c.above = 0.megabytes + c.times = 3 + end + end + end + + # lifecycle + w.lifecycle do |on| + on.condition(:flapping) do |c| + c.to_state = [:start, :restart] + c.times = 5 + c.within = 20.seconds + c.transition = :unmonitored + c.retry_in = 10.seconds + c.retry_times = 2 + c.retry_within = 5.minutes + end + end +end \ No newline at end of file diff --git a/test/configs/complex/simple_server.rb b/test/configs/complex/simple_server.rb new file mode 100755 index 0000000..91b7a25 --- /dev/null +++ b/test/configs/complex/simple_server.rb @@ -0,0 +1,3 @@ +#! /usr/bin/env ruby + +loop { puts 'server'; sleep 1 } \ No newline at end of file -- 2.11.4.GIT