ryansch-bluepill 0.0.53
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/DESIGN.md +10 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +306 -0
- data/Rakefile +9 -0
- data/bin/bluepill +111 -0
- data/bin/bpsv +3 -0
- data/bin/sample_forking_server +53 -0
- data/bluepill.gemspec +29 -0
- data/examples/example.rb +87 -0
- data/examples/new_example.rb +89 -0
- data/examples/new_runit_example.rb +29 -0
- data/examples/runit_example.rb +26 -0
- data/lib/bluepill.rb +36 -0
- data/lib/bluepill/application.rb +203 -0
- data/lib/bluepill/application/client.rb +8 -0
- data/lib/bluepill/application/server.rb +23 -0
- data/lib/bluepill/condition_watch.rb +50 -0
- data/lib/bluepill/controller.rb +121 -0
- data/lib/bluepill/dsl.rb +12 -0
- data/lib/bluepill/dsl/app_proxy.rb +25 -0
- data/lib/bluepill/dsl/process_factory.rb +122 -0
- data/lib/bluepill/dsl/process_proxy.rb +44 -0
- data/lib/bluepill/group.rb +72 -0
- data/lib/bluepill/logger.rb +63 -0
- data/lib/bluepill/process.rb +478 -0
- data/lib/bluepill/process_conditions.rb +14 -0
- data/lib/bluepill/process_conditions/always_true.rb +18 -0
- data/lib/bluepill/process_conditions/cpu_usage.rb +19 -0
- data/lib/bluepill/process_conditions/http.rb +58 -0
- data/lib/bluepill/process_conditions/mem_usage.rb +32 -0
- data/lib/bluepill/process_conditions/process_condition.rb +22 -0
- data/lib/bluepill/process_statistics.rb +23 -0
- data/lib/bluepill/socket.rb +47 -0
- data/lib/bluepill/system.rb +235 -0
- data/lib/bluepill/trigger.rb +60 -0
- data/lib/bluepill/triggers/flapping.rb +56 -0
- data/lib/bluepill/util/rotational_array.rb +20 -0
- data/lib/bluepill/version.rb +4 -0
- metadata +192 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Bluepill
|
3
|
+
class Trigger
|
4
|
+
@implementations = {}
|
5
|
+
def self.inherited(klass)
|
6
|
+
@implementations[klass.name.split('::').last.underscore.to_sym] = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.[](name)
|
10
|
+
@implementations[name]
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :process, :logger, :mutex, :scheduled_events
|
14
|
+
|
15
|
+
def initialize(process, options = {})
|
16
|
+
self.process = process
|
17
|
+
self.logger = options[:logger]
|
18
|
+
self.mutex = Mutex.new
|
19
|
+
self.scheduled_events = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def reset!
|
23
|
+
self.cancel_all_events
|
24
|
+
end
|
25
|
+
|
26
|
+
def notify(transition)
|
27
|
+
raise "Implement in subclass"
|
28
|
+
end
|
29
|
+
|
30
|
+
def dispatch!(event)
|
31
|
+
self.process.dispatch!(event, self.class.name.split("::").last)
|
32
|
+
end
|
33
|
+
|
34
|
+
def schedule_event(event, delay)
|
35
|
+
# TODO: maybe wrap this in a ScheduledEvent class with methods like cancel
|
36
|
+
thread = Thread.new(self) do |trigger|
|
37
|
+
begin
|
38
|
+
sleep delay.to_f
|
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,56 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Bluepill
|
3
|
+
module Triggers
|
4
|
+
class Flapping < Bluepill::Trigger
|
5
|
+
TRIGGER_STATES = [:starting, :restarting]
|
6
|
+
|
7
|
+
PARAMS = [:times, :within, :retry_in]
|
8
|
+
|
9
|
+
attr_accessor *PARAMS
|
10
|
+
attr_reader :timeline
|
11
|
+
|
12
|
+
def initialize(process, options = {})
|
13
|
+
options.reverse_merge!(:times => 5, :within => 1, :retry_in => 5)
|
14
|
+
|
15
|
+
options.each_pair do |name, val|
|
16
|
+
instance_variable_set("@#{name}", val) if PARAMS.include?(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
@timeline = Util::RotationalArray.new(@times)
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def notify(transition)
|
24
|
+
if TRIGGER_STATES.include?(transition.to_name)
|
25
|
+
self.timeline << Time.now.to_i
|
26
|
+
self.check_flapping
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset!
|
31
|
+
@timeline.clear
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
def check_flapping
|
36
|
+
# The process has not flapped if we haven't encountered enough incidents
|
37
|
+
return unless (@timeline.compact.length == self.times)
|
38
|
+
|
39
|
+
# Check if the incident happend within the timeframe
|
40
|
+
duration = (@timeline.last - @timeline.first) <= self.within
|
41
|
+
|
42
|
+
if duration
|
43
|
+
self.logger.info "Flapping detected: retrying in #{self.retry_in} seconds"
|
44
|
+
|
45
|
+
self.schedule_event(:start, self.retry_in) unless self.retry_in == 0 # retry_in zero means "do not retry, ever"
|
46
|
+
self.schedule_event(:unmonitor, 0)
|
47
|
+
|
48
|
+
@timeline.clear
|
49
|
+
|
50
|
+
# This will prevent a transition from happening in the process state_machine
|
51
|
+
throw :halt
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Bluepill
|
3
|
+
module Util
|
4
|
+
class RotationalArray < Array
|
5
|
+
def initialize(size)
|
6
|
+
@capacity = size
|
7
|
+
|
8
|
+
super() # no size - intentionally
|
9
|
+
end
|
10
|
+
|
11
|
+
def push(value)
|
12
|
+
super(value)
|
13
|
+
|
14
|
+
self.shift if self.length > @capacity
|
15
|
+
self
|
16
|
+
end
|
17
|
+
alias_method :<<, :push
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ryansch-bluepill
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 117
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 53
|
10
|
+
version: 0.0.53
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Arya Asemanfar
|
14
|
+
- Gary Tsang
|
15
|
+
- Rohith Ravi
|
16
|
+
- Ryan Schlesinger
|
17
|
+
autorequire:
|
18
|
+
bindir: bin
|
19
|
+
cert_chain: []
|
20
|
+
|
21
|
+
date: 2011-08-19 00:00:00 -07:00
|
22
|
+
default_executable:
|
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: 19
|
33
|
+
segments:
|
34
|
+
- 1
|
35
|
+
- 1
|
36
|
+
- 0
|
37
|
+
version: 1.1.0
|
38
|
+
type: :runtime
|
39
|
+
version_requirements: *id001
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: state_machine
|
42
|
+
prerelease: false
|
43
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
hash: 51
|
49
|
+
segments:
|
50
|
+
- 0
|
51
|
+
- 9
|
52
|
+
- 4
|
53
|
+
version: 0.9.4
|
54
|
+
type: :runtime
|
55
|
+
version_requirements: *id002
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: activesupport
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 7
|
65
|
+
segments:
|
66
|
+
- 3
|
67
|
+
- 0
|
68
|
+
- 0
|
69
|
+
version: 3.0.0
|
70
|
+
type: :runtime
|
71
|
+
version_requirements: *id003
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: i18n
|
74
|
+
prerelease: false
|
75
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 11
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
- 5
|
84
|
+
- 0
|
85
|
+
version: 0.5.0
|
86
|
+
type: :runtime
|
87
|
+
version_requirements: *id004
|
88
|
+
- !ruby/object:Gem::Dependency
|
89
|
+
name: bundler
|
90
|
+
prerelease: false
|
91
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
hash: 3
|
97
|
+
segments:
|
98
|
+
- 1
|
99
|
+
- 0
|
100
|
+
- 10
|
101
|
+
version: 1.0.10
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id005
|
104
|
+
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.
|
105
|
+
email:
|
106
|
+
- ryan@instanceinc.com
|
107
|
+
executables:
|
108
|
+
- bluepill
|
109
|
+
- bpsv
|
110
|
+
- sample_forking_server
|
111
|
+
extensions: []
|
112
|
+
|
113
|
+
extra_rdoc_files:
|
114
|
+
- LICENSE
|
115
|
+
- README.md
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- DESIGN.md
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- bin/bluepill
|
124
|
+
- bin/bpsv
|
125
|
+
- bin/sample_forking_server
|
126
|
+
- bluepill.gemspec
|
127
|
+
- examples/example.rb
|
128
|
+
- examples/new_example.rb
|
129
|
+
- examples/new_runit_example.rb
|
130
|
+
- examples/runit_example.rb
|
131
|
+
- lib/bluepill.rb
|
132
|
+
- lib/bluepill/application.rb
|
133
|
+
- lib/bluepill/application/client.rb
|
134
|
+
- lib/bluepill/application/server.rb
|
135
|
+
- lib/bluepill/condition_watch.rb
|
136
|
+
- lib/bluepill/controller.rb
|
137
|
+
- lib/bluepill/dsl.rb
|
138
|
+
- lib/bluepill/dsl/app_proxy.rb
|
139
|
+
- lib/bluepill/dsl/process_factory.rb
|
140
|
+
- lib/bluepill/dsl/process_proxy.rb
|
141
|
+
- lib/bluepill/group.rb
|
142
|
+
- lib/bluepill/logger.rb
|
143
|
+
- lib/bluepill/process.rb
|
144
|
+
- lib/bluepill/process_conditions.rb
|
145
|
+
- lib/bluepill/process_conditions/always_true.rb
|
146
|
+
- lib/bluepill/process_conditions/cpu_usage.rb
|
147
|
+
- lib/bluepill/process_conditions/http.rb
|
148
|
+
- lib/bluepill/process_conditions/mem_usage.rb
|
149
|
+
- lib/bluepill/process_conditions/process_condition.rb
|
150
|
+
- lib/bluepill/process_statistics.rb
|
151
|
+
- lib/bluepill/socket.rb
|
152
|
+
- lib/bluepill/system.rb
|
153
|
+
- lib/bluepill/trigger.rb
|
154
|
+
- lib/bluepill/triggers/flapping.rb
|
155
|
+
- lib/bluepill/util/rotational_array.rb
|
156
|
+
- lib/bluepill/version.rb
|
157
|
+
has_rdoc: true
|
158
|
+
homepage: http://github.com/ryansch/bluepill
|
159
|
+
licenses: []
|
160
|
+
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options: []
|
163
|
+
|
164
|
+
require_paths:
|
165
|
+
- lib
|
166
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
167
|
+
none: false
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
hash: 3
|
172
|
+
segments:
|
173
|
+
- 0
|
174
|
+
version: "0"
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
none: false
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
hash: 3
|
181
|
+
segments:
|
182
|
+
- 0
|
183
|
+
version: "0"
|
184
|
+
requirements: []
|
185
|
+
|
186
|
+
rubyforge_project:
|
187
|
+
rubygems_version: 1.6.2
|
188
|
+
signing_key:
|
189
|
+
specification_version: 3
|
190
|
+
summary: A process monitor written in Ruby with stability and minimalism in mind.
|
191
|
+
test_files: []
|
192
|
+
|