mrflip-edamame 0.1.1
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/.document +8 -0
- data/.gitignore +31 -0
- data/LICENSE.textile +21 -0
- data/README.textile +178 -0
- data/Rakefile +75 -0
- data/VERSION +1 -0
- data/app/edamame_san/config.ru +4 -0
- data/app/edamame_san/config.yml +17 -0
- data/app/edamame_san/config/.gitignore +1 -0
- data/app/edamame_san/edamame_san.rb +71 -0
- data/app/edamame_san/public/favicon.ico +0 -0
- data/app/edamame_san/public/images/edamame_logo.icns +0 -0
- data/app/edamame_san/public/images/edamame_logo.ico +0 -0
- data/app/edamame_san/public/images/edamame_logo.png +0 -0
- data/app/edamame_san/public/images/edamame_logo_2.icns +0 -0
- data/app/edamame_san/public/javascripts/application.js +8 -0
- data/app/edamame_san/public/javascripts/jquery/jquery-ui.js +8694 -0
- data/app/edamame_san/public/javascripts/jquery/jquery.js +4376 -0
- data/app/edamame_san/public/stylesheets/application.css +32 -0
- data/app/edamame_san/public/stylesheets/layout.css +88 -0
- data/app/edamame_san/views/layout.haml +13 -0
- data/app/edamame_san/views/load.haml +37 -0
- data/app/edamame_san/views/root.haml +25 -0
- data/bin/edamame-ps +2 -0
- data/bin/empty_all.rb +15 -0
- data/bin/stats.rb +13 -0
- data/bin/sync.rb +15 -0
- data/bin/test_run.rb +14 -0
- data/edamame.gemspec +110 -0
- data/lib/edamame.rb +193 -0
- data/lib/edamame/job.rb +134 -0
- data/lib/edamame/queue.rb +6 -0
- data/lib/edamame/queue/beanstalk.rb +132 -0
- data/lib/edamame/rescheduled.rb +89 -0
- data/lib/edamame/scheduling.rb +69 -0
- data/lib/edamame/store.rb +8 -0
- data/lib/edamame/store/base.rb +62 -0
- data/lib/edamame/store/tyrant_store.rb +50 -0
- data/lib/methods.txt +94 -0
- data/spec/edamame_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- data/utils/god/README-god.textile +54 -0
- data/utils/god/beanstalkd_god.rb +34 -0
- data/utils/god/edamame.god +30 -0
- data/utils/god/god-etc-init-dot-d-example +40 -0
- data/utils/god/god_email.rb +45 -0
- data/utils/god/god_process.rb +140 -0
- data/utils/god/god_site_config.rb +4 -0
- data/utils/god/sinatra_god.rb +36 -0
- data/utils/god/tyrant_god.rb +67 -0
- data/utils/simulation/Add Percent Variation.vi +0 -0
- data/utils/simulation/Harmonic Average.vi +0 -0
- data/utils/simulation/Rescheduling Simulation.aliases +3 -0
- data/utils/simulation/Rescheduling Simulation.lvlps +3 -0
- data/utils/simulation/Rescheduling Simulation.lvproj +22 -0
- data/utils/simulation/Rescheduling.vi +0 -0
- data/utils/simulation/Weighted Average.vi +0 -0
- metadata +135 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'tokyotyrant'
|
2
|
+
module Edamame
|
3
|
+
module Store
|
4
|
+
|
5
|
+
#
|
6
|
+
# Implementation of KeyStore with a Local TokyoCabinet table database (TDB)
|
7
|
+
#
|
8
|
+
class TyrantStore < Edamame::Store::Base
|
9
|
+
attr_accessor :db_host, :db_port
|
10
|
+
|
11
|
+
# pass in the host:port uri of the key store.
|
12
|
+
def initialize options
|
13
|
+
self.db_host, self.db_port = options[:uri].to_s.split(':')
|
14
|
+
super options
|
15
|
+
end
|
16
|
+
|
17
|
+
def db
|
18
|
+
return @db if @db
|
19
|
+
@db ||= TokyoTyrant::RDBTBL.new
|
20
|
+
@db.open(db_host, db_port) or raise("Can't open DB #{db_host}:#{db_port}. Pass in host:port' #{@db.ecode}: #{@db.errmsg(@db.ecode)}")
|
21
|
+
@db
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
@db.close if @db
|
26
|
+
@db = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# Save the value into the database without waiting for a response.
|
30
|
+
def set_nr(key, val)
|
31
|
+
db.putnr key, val if val
|
32
|
+
end
|
33
|
+
|
34
|
+
def size()
|
35
|
+
db.rnum
|
36
|
+
end
|
37
|
+
|
38
|
+
def stats
|
39
|
+
{ :size => size }
|
40
|
+
end
|
41
|
+
|
42
|
+
def include? *args
|
43
|
+
db.has_key? *args
|
44
|
+
end
|
45
|
+
|
46
|
+
end #class
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/methods.txt
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
See also:
|
2
|
+
|
3
|
+
http://github.com/kr/beanstalkd/blob/master/doc/protocol.txt
|
4
|
+
|
5
|
+
== Connection ==
|
6
|
+
|
7
|
+
connection.rb: def initialize(addr, default_tube=nil)
|
8
|
+
connection.rb: def connect
|
9
|
+
connection.rb: def close
|
10
|
+
|
11
|
+
connection.rb: def put(body, pri=65536, delay=0, ttr=120)
|
12
|
+
connection.rb: def yput(obj, pri=65536, delay=0, ttr=120)
|
13
|
+
connection.rb: def reserve(timeout=nil)
|
14
|
+
connection.rb: def delete(id)
|
15
|
+
connection.rb: def release(id, pri, delay)
|
16
|
+
connection.rb: def bury(id, pri)
|
17
|
+
|
18
|
+
connection.rb: def use(tube)
|
19
|
+
connection.rb: def watch(tube)
|
20
|
+
connection.rb: def ignore(tube)
|
21
|
+
|
22
|
+
connection.rb: def peek_job(id)
|
23
|
+
connection.rb: def peek_ready()
|
24
|
+
connection.rb: def peek_delayed()
|
25
|
+
connection.rb: def peek_buried()
|
26
|
+
|
27
|
+
connection.rb: def stats()
|
28
|
+
connection.rb: def job_stats(id)
|
29
|
+
|
30
|
+
connection.rb: def stats_tube(tube)
|
31
|
+
connection.rb: def list_tubes()
|
32
|
+
connection.rb: def list_tube_used()
|
33
|
+
connection.rb: def list_tubes_watched(cached=false)
|
34
|
+
|
35
|
+
== Pool ==
|
36
|
+
|
37
|
+
connection.rb: def initialize(addrs, default_tube=nil)
|
38
|
+
connection.rb: def connect()
|
39
|
+
connection.rb: def open_connections()
|
40
|
+
connection.rb: def last_server
|
41
|
+
connection.rb: def put(body, pri=65536, delay=0, ttr=120)
|
42
|
+
connection.rb: def yput(obj, pri=65536, delay=0, ttr=120)
|
43
|
+
connection.rb: def reserve(timeout=nil)
|
44
|
+
connection.rb: def use(tube)
|
45
|
+
connection.rb: def watch(tube)
|
46
|
+
connection.rb: def ignore(tube)
|
47
|
+
connection.rb: def raw_stats()
|
48
|
+
connection.rb: def stats()
|
49
|
+
connection.rb: def raw_stats_tube(tube)
|
50
|
+
connection.rb: def stats_tube(tube)
|
51
|
+
connection.rb: def list_tubes()
|
52
|
+
connection.rb: def list_tube_used()
|
53
|
+
connection.rb: def list_tubes_watched(*args)
|
54
|
+
connection.rb: def remove(conn)
|
55
|
+
connection.rb: def close
|
56
|
+
connection.rb: def peek_ready()
|
57
|
+
connection.rb: def peek_delayed()
|
58
|
+
connection.rb: def peek_buried()
|
59
|
+
connection.rb: def peek_job(id)
|
60
|
+
connection.rb: def call_wrap(c, *args)
|
61
|
+
connection.rb: def retry_wrap(*args)
|
62
|
+
connection.rb: def send_to_each_conn_first_res(*args)
|
63
|
+
connection.rb: def send_to_rand_conn(*args)
|
64
|
+
connection.rb: def send_to_all_conns(*args)
|
65
|
+
connection.rb: def pick_connection()
|
66
|
+
connection.rb: def make_hash(pairs)
|
67
|
+
connection.rb: def map_hash(h)
|
68
|
+
connection.rb: def compact_hash(hash)
|
69
|
+
connection.rb: def sum_hashes(hs)
|
70
|
+
connection.rb: def combine_stats(k, a, b)
|
71
|
+
|
72
|
+
|
73
|
+
== Job ==
|
74
|
+
|
75
|
+
job.rb: def [](name)
|
76
|
+
job.rb: def []=(name, val)
|
77
|
+
job.rb: def ybody()
|
78
|
+
job.rb: def initialize(conn, id, body)
|
79
|
+
job.rb: def delete()
|
80
|
+
job.rb: def put_back(pri=self.pri, delay=0, ttr=self.ttr)
|
81
|
+
job.rb: def release(newpri=pri, delay=0)
|
82
|
+
job.rb: def bury(newpri=pri)
|
83
|
+
job.rb: def stats()
|
84
|
+
job.rb: def timeouts() stats['timeouts'] end
|
85
|
+
job.rb: def time_left() stats['time-left'] end
|
86
|
+
job.rb: def age() stats['age'] end
|
87
|
+
job.rb: def state() stats['state'] end
|
88
|
+
job.rb: def delay() stats['delay'] end
|
89
|
+
job.rb: def pri() stats['pri'] end
|
90
|
+
job.rb: def ttr() stats['ttr'] end
|
91
|
+
job.rb: def server()
|
92
|
+
job.rb: def decay(d=([1, delay].max * 1.3).ceil)
|
93
|
+
job.rb: def to_s
|
94
|
+
job.rb: def inspect
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
Keep running:
|
2
|
+
|
3
|
+
* Worker queue (beanstalkd)
|
4
|
+
* Backing store (ttserver)
|
5
|
+
* Request queue-fed Scrapers (list of scripts)
|
6
|
+
* Feed/Periodic scrapers
|
7
|
+
* Constant scrapers
|
8
|
+
|
9
|
+
* http://god.rubyforge.org/
|
10
|
+
* http://railscasts.com/episodes/130-monitoring-with-god
|
11
|
+
|
12
|
+
sudo gem install god
|
13
|
+
god -c config/mailit.god
|
14
|
+
god status
|
15
|
+
god terminate
|
16
|
+
god log mailit-workling
|
17
|
+
kill `cat log/workling.pid`
|
18
|
+
|
19
|
+
* http://nubyonrails.com/articles/about-this-blog-beanstalk-messaging-queue
|
20
|
+
** The "god.conf":http://pastie.textmate.org/private/ovgxu2ihoicli2ktrwtbew is
|
21
|
+
taken from there.
|
22
|
+
|
23
|
+
h2. Beanstalkd
|
24
|
+
|
25
|
+
*Usage*:
|
26
|
+
|
27
|
+
beanstalkd --help
|
28
|
+
Use: beanstalkd [OPTIONS]
|
29
|
+
|
30
|
+
Options:
|
31
|
+
-d detach
|
32
|
+
-l ADDR listen on address (default is 0.0.0.0)
|
33
|
+
-p PORT listen on port (default is 11300)
|
34
|
+
-u USER become user and group
|
35
|
+
-z SIZE set the maximum job size in bytes (default is 65535)
|
36
|
+
-v show version information
|
37
|
+
-h show this help
|
38
|
+
|
39
|
+
|
40
|
+
h2. Tokyo Tyrant
|
41
|
+
|
42
|
+
*Usage*:
|
43
|
+
|
44
|
+
ttserver --help
|
45
|
+
ttserver: the server of Tokyo Tyrant
|
46
|
+
|
47
|
+
usage:
|
48
|
+
ttserver [-host name] [-port num] [-thnum num] [-tout num] [-dmn]
|
49
|
+
[-pid path] [-kl] [-log path] [-ld|-le] [-ulog path]
|
50
|
+
[-ulim num] [-uas] [-sid num]
|
51
|
+
[-mhost name] [-mport num] [-rts path] [-rcc] [-skel name]
|
52
|
+
[-ext path] [-extpc name period] [-mask expr] [-unmask expr] [dbname]
|
53
|
+
|
54
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class BeanstalkdGod < GodProcess
|
2
|
+
BeanstalkdGod::CONFIG_DEFAULTS = {
|
3
|
+
:listen_on => '0.0.0.0',
|
4
|
+
:port => 11300,
|
5
|
+
:user => nil,
|
6
|
+
:max_job_size => '65535',
|
7
|
+
:max_cpu_usage => 50.percent,
|
8
|
+
:max_mem_usage => 500.megabytes,
|
9
|
+
:monitor_group => 'beanstalkds',
|
10
|
+
:beanstalkd_exe => '/usr/local/bin/beanstalkd',
|
11
|
+
}
|
12
|
+
def initialize *args
|
13
|
+
super *args
|
14
|
+
self.config = BeanstalkdGod::CONFIG_DEFAULTS.compact.merge(self.config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.kind
|
18
|
+
:beanstalkd
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_command
|
22
|
+
[
|
23
|
+
config[:beanstalkd_exe],
|
24
|
+
"-l #{config[:listen_on]}",
|
25
|
+
"-p #{config[:port]}",
|
26
|
+
"-z #{config[:max_job_size]}",
|
27
|
+
config[:user] ? "-u #{config[:user]}" : "",
|
28
|
+
].flatten.compact.join(" ")
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.are_you_there_god_its_me_beanstalkd *args
|
32
|
+
create *args
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
require 'god_process'
|
3
|
+
require 'god_email'
|
4
|
+
require 'beanstalkd_god'
|
5
|
+
require 'tyrant_god'
|
6
|
+
require 'sinatra_god'
|
7
|
+
require 'god_site_config'
|
8
|
+
|
9
|
+
EDAMAME_DB_DIR = '/data/distdb'
|
10
|
+
|
11
|
+
#
|
12
|
+
# For debugging:
|
13
|
+
#
|
14
|
+
# sudo god -c /Users/flip/ics/edamame/utils/god/edamame.god -D
|
15
|
+
#
|
16
|
+
# (for production, use the etc/initc.d script in this directory)
|
17
|
+
#
|
18
|
+
# TODO: define an EdamameDirector that lets us name these collections.
|
19
|
+
#
|
20
|
+
THE_FAITHFUL = [
|
21
|
+
[BeanstalkdGod, { :port => 11210 }],
|
22
|
+
[TyrantGod, { :port => 11212, :db_dirname => EDAMAME_DB_DIR, :db_name => 'flat_delay_queue.tct' }],
|
23
|
+
[TyrantGod, { :port => 11213, :db_dirname => EDAMAME_DB_DIR, :db_name => 'fetched_urls.tch' }],
|
24
|
+
# [SinatraGod, { :port => 11219, :app_dirname => File.dirname(__FILE__)+'/../../app/edamame_san' }],
|
25
|
+
]
|
26
|
+
|
27
|
+
THE_FAITHFUL.each do |klass, config|
|
28
|
+
proc = klass.create(config.merge :flapping_notify => 'default')
|
29
|
+
proc.mkdirs!
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#
|
3
|
+
# God
|
4
|
+
#
|
5
|
+
# chkconfig: - 85 15
|
6
|
+
# description: start, stop, restart God (bet you feel powerful)
|
7
|
+
#
|
8
|
+
#
|
9
|
+
# Make this go with
|
10
|
+
# chmod +x /etc/init.d/god
|
11
|
+
# /usr/sbin/update-rc.d god defaults
|
12
|
+
|
13
|
+
RETVAL=0
|
14
|
+
|
15
|
+
case "$1" in
|
16
|
+
start)
|
17
|
+
/usr/bin/god -P /var/run/god.pid -l /var/log/god.log
|
18
|
+
/usr/bin/god load /etc/god.conf
|
19
|
+
RETVAL=$?
|
20
|
+
;;
|
21
|
+
stop)
|
22
|
+
kill `cat /var/run/god.pid`
|
23
|
+
RETVAL=$?
|
24
|
+
;;
|
25
|
+
restart)
|
26
|
+
kill `cat /var/run/god.pid`
|
27
|
+
/usr/bin/god -P /var/run/god.pid -l /var/log/god.log
|
28
|
+
/usr/bin/god load /etc/god.conf
|
29
|
+
RETVAL=$?
|
30
|
+
;;
|
31
|
+
status)
|
32
|
+
RETVAL=$?
|
33
|
+
;;
|
34
|
+
*)
|
35
|
+
echo "Usage: god {start|stop|restart|status}"
|
36
|
+
exit 1
|
37
|
+
;;
|
38
|
+
esac
|
39
|
+
|
40
|
+
exit $RETVAL
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module God
|
2
|
+
def self.setup_email config
|
3
|
+
God::Contacts::Email.message_settings = {
|
4
|
+
:from => config[:username], }
|
5
|
+
God.contact(:email) do |c|
|
6
|
+
c.name = config[:to_name]
|
7
|
+
c.email = config[:to]
|
8
|
+
c.group = config[:group] || 'default'
|
9
|
+
end
|
10
|
+
if config[:address] then delivery_by_smtp(config)
|
11
|
+
else delivery_by_gmail(config) end
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# GMail
|
16
|
+
#
|
17
|
+
# http://millarian.com/programming/ruby-on-rails/monitoring-thin-using-god-with-google-apps-notifications/
|
18
|
+
def self.delivery_by_gmail config
|
19
|
+
require 'tlsmail'
|
20
|
+
Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
|
21
|
+
God::Contacts::Email.server_settings = {
|
22
|
+
:address => 'smtp.gmail.com',
|
23
|
+
:tls => 'true',
|
24
|
+
:port => 587,
|
25
|
+
:domain => config[:email_domain],
|
26
|
+
:user_name => config[:username],
|
27
|
+
:password => config[:password],
|
28
|
+
:authentication => :plain
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# SMTP email
|
34
|
+
#
|
35
|
+
def self.delivery_by_smtp config
|
36
|
+
God::Contacts::Email.server_settings = {
|
37
|
+
:address => config[:address],
|
38
|
+
:port => 25,
|
39
|
+
:domain => config[:email_domain],
|
40
|
+
:user_name => config[:username],
|
41
|
+
:password => config[:password],
|
42
|
+
:authentication => :plain,
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
class GodProcess
|
2
|
+
CONFIG_DEFAULTS = {
|
3
|
+
:monitor_group => nil,
|
4
|
+
:uid => nil,
|
5
|
+
:gid => nil,
|
6
|
+
:start_notify => nil,
|
7
|
+
:restart_notify => nil,
|
8
|
+
:flapping_notify => nil,
|
9
|
+
|
10
|
+
:process_log_dir => '/var/log/god',
|
11
|
+
|
12
|
+
:start_grace_time => 20.seconds,
|
13
|
+
:restart_grace_time => nil, # start_grace_time+2 if nil
|
14
|
+
:default_interval => 5.minutes,
|
15
|
+
:start_interval => 5.minutes,
|
16
|
+
:mem_usage_interval => 20.minutes,
|
17
|
+
:cpu_usage_interval => 20.minutes,
|
18
|
+
}
|
19
|
+
|
20
|
+
attr_accessor :config
|
21
|
+
def initialize config
|
22
|
+
self.config = CONFIG_DEFAULTS.compact.merge(config)
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
LOG.info config.inspect
|
27
|
+
God.watch do |watcher|
|
28
|
+
config_watcher watcher
|
29
|
+
setup_start watcher
|
30
|
+
setup_restart watcher
|
31
|
+
setup_lifecycle watcher
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def self.create config={}
|
35
|
+
proc = self.new config
|
36
|
+
proc.setup
|
37
|
+
proc
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle
|
41
|
+
(config[:handle] || "#{self.class.kind}_#{config[:port]}").to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_log_file
|
45
|
+
File.join(config[:process_log_dir], handle+".log")
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def mkdirs!
|
50
|
+
require 'fileutils'
|
51
|
+
FileUtils.mkdir_p File.dirname(process_log_file)
|
52
|
+
end
|
53
|
+
|
54
|
+
# command to start the daemon
|
55
|
+
def start_command
|
56
|
+
config[:start_command]
|
57
|
+
end
|
58
|
+
# command to stop the daemon
|
59
|
+
# return nil to have god daemonize the process
|
60
|
+
def stop_command
|
61
|
+
config[:stop_command]
|
62
|
+
end
|
63
|
+
# command to restart
|
64
|
+
# if stop_command is nil, it lets god daemonize the process
|
65
|
+
# otherwise, by default it runs stop_command, pauses for 1 second, then runs start_command
|
66
|
+
def restart_command
|
67
|
+
return unless stop_command
|
68
|
+
[stop_command, "sleep 1", start_command].join(" && ")
|
69
|
+
end
|
70
|
+
|
71
|
+
def config_watcher watcher
|
72
|
+
watcher.name = self.handle
|
73
|
+
watcher.start = start_command
|
74
|
+
watcher.stop = stop_command if stop_command
|
75
|
+
watcher.restart = restart_command if restart_command
|
76
|
+
watcher.group = config[:monitor_group] if config[:monitor_group]
|
77
|
+
watcher.uid = config[:uid] if config[:uid]
|
78
|
+
watcher.gid = config[:gid] if config[:gid]
|
79
|
+
watcher.interval = config[:default_interval]
|
80
|
+
watcher.start_grace = config[:start_grace_time]
|
81
|
+
watcher.restart_grace = config[:restart_grace_time] || (config[:start_grace_time] + 2.seconds)
|
82
|
+
watcher.behavior(:clean_pid_file)
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
def setup_start watcher
|
87
|
+
watcher.start_if do |start|
|
88
|
+
start.condition(:process_running) do |c|
|
89
|
+
c.interval = config[:start_interval]
|
90
|
+
c.running = false
|
91
|
+
c.notify = config[:start_notify] if config[:start_notify]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
def setup_restart watcher
|
98
|
+
watcher.restart_if do |restart|
|
99
|
+
restart.condition(:memory_usage) do |c|
|
100
|
+
c.interval = config[:mem_usage_interval] if config[:mem_usage_interval]
|
101
|
+
c.above = config[:max_mem_usage] || 150.megabytes
|
102
|
+
c.times = [3, 5] # 3 out of 5 intervals
|
103
|
+
c.notify = config[:restart_notify] if config[:restart_notify]
|
104
|
+
end
|
105
|
+
restart.condition(:cpu_usage) do |c|
|
106
|
+
c.interval = config[:cpu_usage_interval] if config[:cpu_usage_interval]
|
107
|
+
c.above = config[:max_cpu_usage] || 50.percent
|
108
|
+
c.times = 5
|
109
|
+
c.notify = config[:restart_notify] if config[:restart_notify]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Define lifecycle
|
115
|
+
def setup_lifecycle watcher
|
116
|
+
watcher.lifecycle do |on|
|
117
|
+
on.condition(:flapping) do |c|
|
118
|
+
c.to_state = [:start, :restart]
|
119
|
+
c.times = 10
|
120
|
+
c.within = 15.minute
|
121
|
+
c.transition = :unmonitored
|
122
|
+
c.retry_in = 60.minutes
|
123
|
+
c.retry_times = 5
|
124
|
+
c.retry_within = 12.hours
|
125
|
+
c.notify = config[:flapping_notify] if config[:flapping_notify]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Hash
|
132
|
+
# remove all key-value pairs where the value is nil
|
133
|
+
def compact
|
134
|
+
reject{|key,val| val.nil? }
|
135
|
+
end
|
136
|
+
# Replace the hash with its compacted self
|
137
|
+
def compact!
|
138
|
+
replace(compact)
|
139
|
+
end
|
140
|
+
end
|