sumskyi-bluepill 0.0.42.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ module Bluepill
2
+ class Trigger
3
+ @implementations = {}
4
+ def self.inherited(klass)
5
+ @implementations[klass.name.split('::').last.underscore.to_sym] = klass
6
+ end
7
+
8
+ def self.[](name)
9
+ @implementations[name]
10
+ end
11
+
12
+ attr_accessor :process, :logger, :mutex, :scheduled_events
13
+
14
+ def initialize(process, options = {})
15
+ self.process = process
16
+ self.logger = options[:logger]
17
+ self.mutex = Mutex.new
18
+ self.scheduled_events = []
19
+ end
20
+
21
+ def reset!
22
+ self.cancel_all_events
23
+ end
24
+
25
+ def notify(transition)
26
+ raise "Implement in subclass"
27
+ end
28
+
29
+ def dispatch!(event)
30
+ self.process.dispatch!(event, self.class.name.split("::").last)
31
+ end
32
+
33
+ def schedule_event(event, delay)
34
+ # TODO: maybe wrap this in a ScheduledEvent class with methods like cancel
35
+ thread = Thread.new(self) do |trigger|
36
+ begin
37
+ sleep delay.to_f
38
+ trigger.logger.info("Retrying from flapping")
39
+ trigger.dispatch!(event)
40
+ trigger.mutex.synchronize do
41
+ trigger.scheduled_events.delete_if { |_, thread| thread == Thread.current }
42
+ end
43
+ rescue StandardError => e
44
+ trigger.logger.err(e)
45
+ trigger.logger.err(e.backtrace.join("\n"))
46
+ end
47
+ end
48
+
49
+ self.scheduled_events.push([event, thread])
50
+ end
51
+
52
+ def cancel_all_events
53
+ self.logger.info "Canceling all scheduled events"
54
+ self.mutex.synchronize do
55
+ self.scheduled_events.each {|_, thread| thread.kill}
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,59 @@
1
+ module Bluepill
2
+ module Triggers
3
+ class Flapping < Bluepill::Trigger
4
+ TRIGGER_STATES = [:starting, :restarting]
5
+
6
+ PARAMS = [:times, :within, :retry_in]
7
+
8
+ attr_accessor *PARAMS
9
+ attr_reader :timeline
10
+
11
+ def initialize(process, options = {})
12
+ options.reverse_merge!(:times => 5, :within => 1, :retry_in => 5)
13
+
14
+ options.each_pair do |name, val|
15
+ instance_variable_set("@#{name}", val) if PARAMS.include?(name)
16
+ end
17
+
18
+ @timeline = Util::RotationalArray.new(@times)
19
+ super
20
+ end
21
+
22
+ def notify(transition)
23
+ if TRIGGER_STATES.include?(transition.to_name)
24
+ self.timeline << Time.now.to_i
25
+ self.check_flapping
26
+ end
27
+ end
28
+
29
+ def reset!
30
+ @timeline.clear
31
+ super
32
+ end
33
+
34
+ def check_flapping
35
+ num_occurances = (@timeline.nitems == self.times)
36
+
37
+ # The process has not flapped if we haven't encountered enough incidents
38
+ return unless num_occurances
39
+
40
+ # Check if the incident happend within the timeframe
41
+ duration = (@timeline.last - @timeline.first) <= self.within
42
+
43
+ if duration
44
+ self.logger.info "Flapping detected: retrying in #{self.retry_in} seconds"
45
+
46
+ self.schedule_event(:start, self.retry_in)
47
+
48
+ # this happens in the process' thread so we don't have to worry about concurrency issues with this event
49
+ self.dispatch!(:unmonitor)
50
+
51
+ @timeline.clear
52
+
53
+ # This will prevent a transition from happening in the process state_machine
54
+ throw :halt
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,72 @@
1
+ module Bluepill
2
+ module Util
3
+ class RotationalArray < Array
4
+ def initialize(size)
5
+ super(size)
6
+
7
+ @capacity = size
8
+ @counter = 0
9
+ end
10
+
11
+ def push(value)
12
+ idx = rotational_idx(@counter)
13
+ self[idx] = value
14
+
15
+ @counter += 1
16
+ self
17
+ end
18
+
19
+ alias_method :<<, :push
20
+
21
+ def pop
22
+ raise "Cannot call pop on a rotational array"
23
+ end
24
+
25
+ def shift
26
+ raise "Cannot call shift on a rotational array"
27
+ end
28
+
29
+ def unshift
30
+ raise "Cannot call unshift on a rotational array"
31
+ end
32
+
33
+ def last
34
+ return if @counter.zero?
35
+
36
+ self[rotational_idx(@counter - 1)]
37
+ end
38
+
39
+ def first
40
+ return if @counter.zero?
41
+ return self[0] if @counter <= @capacity
42
+
43
+ self[rotational_idx(@counter)]
44
+ end
45
+
46
+ def clear
47
+ @counter = 0
48
+ super
49
+ end
50
+
51
+ def each(&block)
52
+ times = @counter >= @capacity ? @capacity : @counter
53
+ start = @counter >= @capacity ? rotational_idx(@counter) : 0
54
+ times.times do |i|
55
+ block.call(self[rotational_idx(start + i)])
56
+ end
57
+ end
58
+
59
+ unless method_defined?(:nitems)
60
+ def nitems
61
+ compact.length
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def rotational_idx(idx)
68
+ idx % @capacity
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ module Bluepill
2
+ VERSION = "0.0.42"
3
+ end
@@ -0,0 +1,81 @@
1
+ require 'rubygems'
2
+ require 'bluepill'
3
+ require 'logger'
4
+
5
+ ROOT_DIR = "/tmp/bp"
6
+
7
+ # Watch with
8
+ # watch -n0.2 'ps axu | egrep "(CPU|forking|bluepill|sleep)" | grep -v grep | sort'
9
+ Bluepill.application(:sample_app) do |app|
10
+ 0.times do |i|
11
+ app.process("process_#{i}") do |process|
12
+ process.pid_file = "#{ROOT_DIR}/pids/process_#{i}.pid"
13
+
14
+ # I could not figure out a portable way to
15
+ # specify the path to the sample forking server across the diff developer laptops.
16
+ # Since this code is eval'ed we cannot reliably use __FILE__
17
+ process.start_command = "/Users/rohith/work/bluepill/bin/sample_forking_server #{4242 + i}"
18
+ process.stop_command = "kill -INT {{PID}}"
19
+ process.daemonize = true
20
+
21
+ process.start_grace_time = 1.seconds
22
+ process.restart_grace_time = 7.seconds
23
+ process.stop_grace_time = 7.seconds
24
+
25
+ process.uid = "rohith"
26
+ process.gid = "staff"
27
+
28
+ # process.checks :cpu_usage, :every => 10, :below => 0.5, :times => [5, 5]
29
+ process.checks :flapping, :times => 2, :within => 30.seconds, :retry_in => 7.seconds
30
+
31
+ process.monitor_children do |child_process|
32
+ # child_process.checks :cpu_usage,
33
+ # :every => 10,
34
+ # :below => 0.5,
35
+ # :times => [5, 5]
36
+
37
+ # child_process.checks :mem_usage,
38
+ # :every => 3,
39
+ # :below => 600.kilobytes,
40
+ # :times => [3, 5],
41
+ # :fires => [:stop]
42
+
43
+ child_process.stop_command = "kill -QUIT {{PID}}"
44
+ # child_process.checks :flapping, :times => 2, :within => 30.seconds, :retry_in => 7.seconds
45
+ end
46
+ end
47
+ end
48
+
49
+ 0.times do |i|
50
+ app.process("group_process_#{i}") do |process|
51
+ process.group = "group_1"
52
+ process.pid_file = "/Users/rohith/ffs/tmp/pids/mongrel_#{i}.pid"
53
+ process.start_command = "cd ~/ffs && mongrel_rails start -P #{process.pid_file} -p 3000 -d"
54
+
55
+ process.start_grace_time = 10.seconds
56
+
57
+ process.uid = "rohith"
58
+ process.gid = "staff"
59
+
60
+ # process.checks :always_true, :every => 10
61
+ end
62
+ end
63
+
64
+ 1.times do |i|
65
+ app.process("group_process_#{i}") do |process|
66
+ process.uid = "rohith"
67
+ process.gid = "wheel"
68
+
69
+ process.stderr = "/tmp/err.log"
70
+ process.stdout = "/tmp/err.log"
71
+
72
+
73
+ process.group = "grouped"
74
+ process.start_command = %Q{cd /tmp && ruby -e '$stderr.puts("hello stderr");$stdout.puts("hello stdout"); $stdout.flush; $stderr.flush; sleep 10'}
75
+ process.daemonize = true
76
+ process.pid_file = "/tmp/noperm/p_#{process.group}_#{i}.pid"
77
+
78
+ # process.checks :always_true, :every => 5
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'bluepill'
3
+ require 'logger'
4
+
5
+ # ATTENTION:
6
+ # You must declare only one application per config when foreground mode specified
7
+ #
8
+ # http://github.com/akzhan/runit-man used as example of monitored application.
9
+
10
+ Bluepill.application(:runit_man, :foreground => true) do |app|
11
+ app.process("runit-man") do |process|
12
+ process.pid_file = "/etc/service/runit-man/supervise/pid"
13
+
14
+ process.start_command = "/usr/bin/sv start runit-man"
15
+ process.stop_command = "/usr/bin/sv stop runit-man"
16
+ process.restart_command = "/usr/bin/sv restart runit-man"
17
+
18
+ process.start_grace_time = 1.seconds
19
+ process.restart_grace_time = 7.seconds
20
+ process.stop_grace_time = 7.seconds
21
+
22
+ process.checks :http, :within => 30.seconds, :retry_in => 7.seconds, :every => 30.seconds,
23
+ :url => 'http://localhost:4567/', :kind => :success, :pattern => /html/, :timeout => 3.seconds
24
+ end
25
+ end
@@ -0,0 +1,85 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{sumskyi-bluepill}
8
+ s.version = "0.0.42.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
12
+ s.date = %q{2010-08-23}
13
+ s.default_executable = %q{bluepill}
14
+ s.description = %q{Bluepill keeps your daemons up while taking up as little resources as possible. After all you probably want the resources of your server to be used by whatever daemons you are running rather than the thing that's supposed to make sure they are brought back up, should they die or misbehave.}
15
+ s.email = %q{sumskyi@gmail.com}
16
+ s.executables = ["bluepill"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".gitignore",
23
+ "DESIGN.md",
24
+ "LICENSE",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/bluepill",
29
+ "bin/bpsv",
30
+ "sumskyi-bluepill.gemspec",
31
+ "lib/bluepill.rb",
32
+ "lib/bluepill/application.rb",
33
+ "lib/bluepill/application/client.rb",
34
+ "lib/bluepill/application/server.rb",
35
+ "lib/bluepill/condition_watch.rb",
36
+ "lib/bluepill/controller.rb",
37
+ "lib/bluepill/dsl.rb",
38
+ "lib/bluepill/group.rb",
39
+ "lib/bluepill/logger.rb",
40
+ "lib/bluepill/process.rb",
41
+ "lib/bluepill/process_conditions.rb",
42
+ "lib/bluepill/process_conditions/always_true.rb",
43
+ "lib/bluepill/process_conditions/cpu_usage.rb",
44
+ "lib/bluepill/process_conditions/http.rb",
45
+ "lib/bluepill/process_conditions/mem_usage.rb",
46
+ "lib/bluepill/process_conditions/process_condition.rb",
47
+ "lib/bluepill/process_statistics.rb",
48
+ "lib/bluepill/socket.rb",
49
+ "lib/bluepill/system.rb",
50
+ "lib/bluepill/trigger.rb",
51
+ "lib/bluepill/triggers/flapping.rb",
52
+ "lib/bluepill/util/rotational_array.rb",
53
+ "lib/bluepill/version.rb",
54
+ "lib/example.rb",
55
+ "lib/runit_example.rb"
56
+ ]
57
+ s.homepage = %q{http://github.com/arya/bluepill}
58
+ s.rdoc_options = ["--charset=UTF-8"]
59
+ s.require_paths = ["lib"]
60
+ s.rubygems_version = %q{1.3.7}
61
+ s.summary = %q{A process monitor written in Ruby with stability and minimalism in mind.}
62
+
63
+ if s.respond_to? :specification_version then
64
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
65
+ s.specification_version = 3
66
+
67
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
68
+ s.add_runtime_dependency(%q<daemons>, [">= 1.0.9"])
69
+ s.add_runtime_dependency(%q<blankslate>, [">= 2.1.2.2"])
70
+ s.add_runtime_dependency(%q<state_machine>, [">= 0.8.0"])
71
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.4"])
72
+ else
73
+ s.add_dependency(%q<daemons>, [">= 1.0.9"])
74
+ s.add_dependency(%q<blankslate>, [">= 2.1.2.2"])
75
+ s.add_dependency(%q<state_machine>, [">= 0.8.0"])
76
+ s.add_dependency(%q<activesupport>, [">= 2.3.4"])
77
+ end
78
+ else
79
+ s.add_dependency(%q<daemons>, [">= 1.0.9"])
80
+ s.add_dependency(%q<blankslate>, [">= 2.1.2.2"])
81
+ s.add_dependency(%q<state_machine>, [">= 0.8.0"])
82
+ s.add_dependency(%q<activesupport>, [">= 2.3.4"])
83
+ end
84
+ end
85
+
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sumskyi-bluepill
3
+ version: !ruby/object:Gem::Version
4
+ hash: 231
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 42
10
+ - 0
11
+ version: 0.0.42.0
12
+ platform: ruby
13
+ authors:
14
+ - Arya Asemanfar
15
+ - Gary Tsang
16
+ - Rohith Ravi
17
+ autorequire:
18
+ bindir: bin
19
+ cert_chain: []
20
+
21
+ date: 2010-08-23 00:00:00 +03:00
22
+ default_executable: bluepill
23
+ dependencies:
24
+ - !ruby/object:Gem::Dependency
25
+ name: daemons
26
+ prerelease: false
27
+ requirement: &id001 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ hash: 5
33
+ segments:
34
+ - 1
35
+ - 0
36
+ - 9
37
+ version: 1.0.9
38
+ type: :runtime
39
+ version_requirements: *id001
40
+ - !ruby/object:Gem::Dependency
41
+ name: blankslate
42
+ prerelease: false
43
+ requirement: &id002 !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ hash: 107
49
+ segments:
50
+ - 2
51
+ - 1
52
+ - 2
53
+ - 2
54
+ version: 2.1.2.2
55
+ type: :runtime
56
+ version_requirements: *id002
57
+ - !ruby/object:Gem::Dependency
58
+ name: state_machine
59
+ prerelease: false
60
+ requirement: &id003 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 63
66
+ segments:
67
+ - 0
68
+ - 8
69
+ - 0
70
+ version: 0.8.0
71
+ type: :runtime
72
+ version_requirements: *id003
73
+ - !ruby/object:Gem::Dependency
74
+ name: activesupport
75
+ prerelease: false
76
+ requirement: &id004 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 11
82
+ segments:
83
+ - 2
84
+ - 3
85
+ - 4
86
+ version: 2.3.4
87
+ type: :runtime
88
+ version_requirements: *id004
89
+ description: Bluepill keeps your daemons up while taking up as little resources as possible. After all you probably want the resources of your server to be used by whatever daemons you are running rather than the thing that's supposed to make sure they are brought back up, should they die or misbehave.
90
+ email: sumskyi@gmail.com
91
+ executables:
92
+ - bluepill
93
+ extensions: []
94
+
95
+ extra_rdoc_files:
96
+ - LICENSE
97
+ - README.md
98
+ files:
99
+ - .gitignore
100
+ - DESIGN.md
101
+ - LICENSE
102
+ - README.md
103
+ - Rakefile
104
+ - VERSION
105
+ - bin/bluepill
106
+ - bin/bpsv
107
+ - sumskyi-bluepill.gemspec
108
+ - lib/bluepill.rb
109
+ - lib/bluepill/application.rb
110
+ - lib/bluepill/application/client.rb
111
+ - lib/bluepill/application/server.rb
112
+ - lib/bluepill/condition_watch.rb
113
+ - lib/bluepill/controller.rb
114
+ - lib/bluepill/dsl.rb
115
+ - lib/bluepill/group.rb
116
+ - lib/bluepill/logger.rb
117
+ - lib/bluepill/process.rb
118
+ - lib/bluepill/process_conditions.rb
119
+ - lib/bluepill/process_conditions/always_true.rb
120
+ - lib/bluepill/process_conditions/cpu_usage.rb
121
+ - lib/bluepill/process_conditions/http.rb
122
+ - lib/bluepill/process_conditions/mem_usage.rb
123
+ - lib/bluepill/process_conditions/process_condition.rb
124
+ - lib/bluepill/process_statistics.rb
125
+ - lib/bluepill/socket.rb
126
+ - lib/bluepill/system.rb
127
+ - lib/bluepill/trigger.rb
128
+ - lib/bluepill/triggers/flapping.rb
129
+ - lib/bluepill/util/rotational_array.rb
130
+ - lib/bluepill/version.rb
131
+ - lib/example.rb
132
+ - lib/runit_example.rb
133
+ has_rdoc: true
134
+ homepage: http://github.com/arya/bluepill
135
+ licenses: []
136
+
137
+ post_install_message:
138
+ rdoc_options:
139
+ - --charset=UTF-8
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ none: false
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ hash: 3
148
+ segments:
149
+ - 0
150
+ version: "0"
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ none: false
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ hash: 3
157
+ segments:
158
+ - 0
159
+ version: "0"
160
+ requirements: []
161
+
162
+ rubyforge_project:
163
+ rubygems_version: 1.3.7
164
+ signing_key:
165
+ specification_version: 3
166
+ summary: A process monitor written in Ruby with stability and minimalism in mind.
167
+ test_files: []
168
+