eye 0.6.4 → 0.7.pre
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGES.md +5 -0
- data/Gemfile +0 -4
- data/README.md +9 -2
- data/Rakefile +12 -2
- data/examples/dependency.eye +21 -0
- data/examples/stress_test.eye +1 -1
- data/examples/triggers.eye +9 -0
- data/eye.gemspec +5 -2
- data/lib/eye.rb +1 -1
- data/lib/eye/checker/http.rb +11 -1
- data/lib/eye/config.rb +5 -2
- data/lib/eye/controller.rb +3 -2
- data/lib/eye/controller/commands.rb +1 -0
- data/lib/eye/dsl/main.rb +5 -0
- data/lib/eye/dsl/opts.rb +5 -7
- data/lib/eye/dsl/process_opts.rb +2 -0
- data/lib/eye/dsl/validation.rb +2 -2
- data/lib/eye/group.rb +5 -1
- data/lib/eye/group/chain.rb +5 -0
- data/lib/eye/loader.rb +2 -2
- data/lib/eye/notify.rb +2 -1
- data/lib/eye/notify/slack.rb +38 -0
- data/lib/eye/process.rb +1 -3
- data/lib/eye/process/config.rb +11 -0
- data/lib/eye/process/controller.rb +4 -0
- data/lib/eye/process/data.rb +1 -1
- data/lib/eye/process/scheduler.rb +17 -0
- data/lib/eye/process/states_history.rb +1 -39
- data/lib/eye/process/trigger.rb +13 -5
- data/lib/eye/reason.rb +3 -0
- data/lib/eye/system_resources.rb +6 -2
- data/lib/eye/trigger.rb +13 -1
- data/lib/eye/trigger/check_dependency.rb +1 -1
- data/lib/eye/trigger/flapping.rb +9 -3
- data/lib/eye/trigger/starting_guard.rb +64 -0
- data/lib/eye/trigger/transition.rb +1 -5
- data/lib/eye/utils.rb +13 -0
- metadata +51 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 488ed21561da07936dd5fbc3e0d869e4665ba4a5
|
4
|
+
data.tar.gz: 12b6d6c69ee5e0bf9409bb61e700a6525d1d386a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54a0993fb03ecf29c9f8a572c977aeb6856da53b972f6d3555c1e17fef13bc807fdfb819ed968f4571f5ee3dd05c8faf0cf766a77be6017ac81e007927605438
|
7
|
+
data.tar.gz: 3023586158006d3c76ba25675b88bfc2eb0977cafc748b928437ab1cf74178d4494e229e6028615ae8c1efc667188566b0801f5739fa565a94026e6cd737fb56
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -28,7 +28,7 @@ I hope we've succeeded, we're using eye in production and are quite happy.
|
|
28
28
|
|
29
29
|
### Config example
|
30
30
|
|
31
|
-
examples/test.eye
|
31
|
+
examples/test.eye ([more examples](https://github.com/kostya/eye/tree/master/examples))
|
32
32
|
```ruby
|
33
33
|
# load submodules, here just for example
|
34
34
|
Eye.load('./eye/*.rb')
|
@@ -200,16 +200,23 @@ Eye daemon info:
|
|
200
200
|
$ eye x(info)
|
201
201
|
$ eye x -c # for show current config
|
202
202
|
|
203
|
+
Local Eye version LEye (like foreman):
|
204
|
+
|
205
|
+
[LEye](https://github.com/kostya/eye/wiki/What-is-loader_eye-and-leye)
|
206
|
+
|
203
207
|
Process states and events:
|
204
208
|
|
205
209
|
[](https://raw.github.com/kostya/stuff/master/eye/process.png)
|
206
210
|
|
211
|
+
How to write Eye extensions, plugins, gems:
|
212
|
+
|
213
|
+
[Eye-http](https://github.com/kostya/eye-http) [Eye-rotate](https://github.com/kostya/eye-rotate) [Eye-hipchat](https://github.com/tmeinlschmidt/eye-hipchat) [Plugin example](https://github.com/kostya/eye/tree/master/examples/plugin)
|
207
214
|
|
208
215
|
[Eye related projects](https://github.com/kostya/eye/wiki/Related-projects)
|
209
216
|
|
210
217
|
[Articles](https://github.com/kostya/eye/wiki/Articles)
|
211
218
|
|
212
|
-
[
|
219
|
+
[Wiki](https://github.com/kostya/eye/wiki)
|
213
220
|
|
214
221
|
|
215
222
|
Thanks `Bluepill` for the nice config ideas.
|
data/Rakefile
CHANGED
@@ -2,15 +2,25 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require 'rspec/core/rake_task'
|
5
|
-
require 'parallel_tests/tasks'
|
6
5
|
require 'coveralls/rake/task'
|
7
6
|
|
8
7
|
Coveralls::RakeTask.new
|
9
8
|
|
10
9
|
task :default => :pspec
|
11
10
|
|
11
|
+
desc "run parallel tests"
|
12
12
|
task :pspec do
|
13
|
-
|
13
|
+
dirname = File.expand_path(File.dirname(__FILE__))
|
14
|
+
cmd = "bundle exec parallel_rspec -n #{ENV['N'] || 10} --runtime-log '#{dirname}/spec/weights.txt' #{dirname}/spec"
|
15
|
+
abort unless system(cmd)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "run parallel split tests"
|
19
|
+
task :split_test do
|
20
|
+
dirname = File.expand_path(File.dirname(__FILE__))
|
21
|
+
ENV['PARALLEL_SPLIT_TEST_PROCESSES'] = (ENV['N'] || 10).to_s
|
22
|
+
cmd = "bundle exec parallel_split_test #{dirname}/spec"
|
23
|
+
abort unless system(cmd)
|
14
24
|
end
|
15
25
|
|
16
26
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
data/examples/dependency.eye
CHANGED
@@ -14,4 +14,25 @@ Eye.app :dependency do
|
|
14
14
|
depend_on :a
|
15
15
|
end
|
16
16
|
|
17
|
+
process(:c) do
|
18
|
+
start_command "sleep 100"
|
19
|
+
daemonize true
|
20
|
+
pid_file "/tmp/test_process_c.pid"
|
21
|
+
depend_on :a
|
22
|
+
end
|
23
|
+
|
24
|
+
process(:d) do
|
25
|
+
start_command "sleep 100"
|
26
|
+
daemonize true
|
27
|
+
pid_file "/tmp/test_process_d.pid"
|
28
|
+
depend_on :b
|
29
|
+
end
|
30
|
+
|
31
|
+
process(:e) do
|
32
|
+
start_command "sleep 100"
|
33
|
+
daemonize true
|
34
|
+
pid_file "/tmp/test_process_e.pid"
|
35
|
+
depend_on [:d, :c]
|
36
|
+
end
|
37
|
+
|
17
38
|
end
|
data/examples/stress_test.eye
CHANGED
data/examples/triggers.eye
CHANGED
@@ -52,4 +52,13 @@ Eye.app :triggers do
|
|
52
52
|
}
|
53
53
|
end
|
54
54
|
|
55
|
+
# process d cant start, until file /tmp/bla contains string 'bla'
|
56
|
+
process :d do
|
57
|
+
pid_file "/tmp/d.pid"
|
58
|
+
start_command "sleep 100"
|
59
|
+
daemonize true
|
60
|
+
|
61
|
+
trigger :starting_guard, every: 5.seconds, should: -> { `cat /tmp/bla` =~ /bla/ }
|
62
|
+
end
|
63
|
+
|
55
64
|
end
|
data/eye.gemspec
CHANGED
@@ -19,8 +19,8 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.required_ruby_version = '>= 1.9.2'
|
20
20
|
gem.required_rubygems_version = '>= 1.3.6'
|
21
21
|
|
22
|
-
gem.add_dependency 'celluloid', '~> 0.
|
23
|
-
gem.add_dependency 'celluloid-io', '~> 0.
|
22
|
+
gem.add_dependency 'celluloid', '~> 0.16.0'
|
23
|
+
gem.add_dependency 'celluloid-io', '~> 0.16.0'
|
24
24
|
gem.add_dependency 'state_machine'
|
25
25
|
gem.add_dependency 'thor'
|
26
26
|
gem.add_dependency 'sigar', '~> 0.7.2'
|
@@ -35,6 +35,9 @@ Gem::Specification.new do |gem|
|
|
35
35
|
gem.add_development_dependency 'sinatra'
|
36
36
|
gem.add_development_dependency 'thin'
|
37
37
|
gem.add_development_dependency 'xmpp4r'
|
38
|
+
gem.add_development_dependency 'slack-notifier'
|
38
39
|
gem.add_development_dependency 'coveralls'
|
39
40
|
gem.add_development_dependency 'simplecov', '>= 0.8.1'
|
41
|
+
gem.add_development_dependency 'parallel_tests', '<= 1.3.1'
|
42
|
+
gem.add_development_dependency 'parallel_split_test'
|
40
43
|
end
|
data/lib/eye.rb
CHANGED
data/lib/eye/checker/http.rb
CHANGED
@@ -6,6 +6,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
|
|
6
6
|
# :url => "http://127.0.0.1:3000/", :kind => :success, :pattern => /OK/, :timeout => 3.seconds
|
7
7
|
|
8
8
|
param :url, String, true
|
9
|
+
param :proxy_url, String
|
9
10
|
param :pattern, [String, Regexp]
|
10
11
|
param :kind, [String, Fixnum, Symbol]
|
11
12
|
param :timeout, [Fixnum, Float]
|
@@ -18,6 +19,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
|
|
18
19
|
super
|
19
20
|
|
20
21
|
@uri = URI.parse(url)
|
22
|
+
@proxy_uri = URI.parse(proxy_url) if proxy_url
|
21
23
|
@kind = case kind
|
22
24
|
when Fixnum then Net::HTTPResponse::CODE_TO_OBJ[kind]
|
23
25
|
when String, Symbol then Net.const_get("HTTP#{kind.to_s.camelize}") rescue Net::HTTPSuccess
|
@@ -82,15 +84,23 @@ class Eye::Checker::Http < Eye::Checker::Defer
|
|
82
84
|
private
|
83
85
|
|
84
86
|
def session
|
85
|
-
|
87
|
+
net_http.tap do |session|
|
86
88
|
if @uri.scheme == 'https'
|
87
89
|
require 'net/https'
|
88
90
|
session.use_ssl = true
|
89
91
|
session.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
90
92
|
end
|
93
|
+
|
91
94
|
session.open_timeout = @open_timeout
|
92
95
|
session.read_timeout = @read_timeout
|
93
96
|
end
|
94
97
|
end
|
95
98
|
|
99
|
+
def net_http
|
100
|
+
if @proxy_uri
|
101
|
+
Net::HTTP.new(@uri.host, @uri.port, @proxy_uri.host, @proxy_uri.port)
|
102
|
+
else
|
103
|
+
Net::HTTP.new(@uri.host, @uri.port)
|
104
|
+
end
|
105
|
+
end
|
96
106
|
end
|
data/lib/eye/config.rb
CHANGED
@@ -8,11 +8,14 @@ class Eye::Config
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def merge(other_config)
|
11
|
-
|
11
|
+
new_settings = {}
|
12
|
+
Eye::Utils.deep_merge!(new_settings, @settings)
|
13
|
+
Eye::Utils.deep_merge!(new_settings, other_config.settings)
|
14
|
+
Eye::Config.new(new_settings, @applications.merge(other_config.applications))
|
12
15
|
end
|
13
16
|
|
14
17
|
def merge!(other_config)
|
15
|
-
|
18
|
+
Eye::Utils.deep_merge!(@settings, other_config.settings)
|
16
19
|
@applications.merge!(other_config.applications)
|
17
20
|
end
|
18
21
|
|
data/lib/eye/controller.rb
CHANGED
@@ -10,7 +10,9 @@ require_relative 'utils/mini_active_support'
|
|
10
10
|
# Extend all objects with logger
|
11
11
|
Object.send(:include, Eye::Logger::ObjectExt)
|
12
12
|
|
13
|
-
|
13
|
+
# needs to preload
|
14
|
+
Eye::Sigar
|
15
|
+
Eye::SystemResources
|
14
16
|
|
15
17
|
class Eye::Controller
|
16
18
|
include Celluloid
|
@@ -36,7 +38,6 @@ class Eye::Controller
|
|
36
38
|
@current_config = Eye::Config.new
|
37
39
|
|
38
40
|
Celluloid::logger = Eye::Logger.new('celluloid')
|
39
|
-
Eye::SystemResources.cache
|
40
41
|
|
41
42
|
info "starting #{Eye::ABOUT} <#{$$}>"
|
42
43
|
end
|
data/lib/eye/dsl/main.rb
CHANGED
data/lib/eye/dsl/opts.rb
CHANGED
@@ -196,15 +196,13 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
|
|
196
196
|
end
|
197
197
|
raise Eye::Dsl::Error, "load_env conflict filenames: #{filenames}" if filenames.size > 1
|
198
198
|
|
199
|
-
content = File.read(filenames.first)
|
200
199
|
info "load_env from '#{filenames.first}'"
|
200
|
+
Eye::Utils.load_env(filenames.first).each { |k, v| env k => v }
|
201
|
+
end
|
201
202
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
k, *v = e.split('=')
|
206
|
-
env k => v.join('=')
|
207
|
-
end
|
203
|
+
def skip_group_action(act, val = true)
|
204
|
+
@config[:skip_group_actions] ||= {}
|
205
|
+
@config[:skip_group_actions][act] = val
|
208
206
|
end
|
209
207
|
|
210
208
|
private
|
data/lib/eye/dsl/process_opts.rb
CHANGED
data/lib/eye/dsl/validation.rb
CHANGED
@@ -32,7 +32,7 @@ module Eye::Dsl::Validation
|
|
32
32
|
|
33
33
|
define_method "#{param}" do
|
34
34
|
value = @options[param]
|
35
|
-
value.nil? ?
|
35
|
+
value.nil? ? self.class.defaults[param] : value
|
36
36
|
end
|
37
37
|
|
38
38
|
define_method "#{param}=" do |value|
|
@@ -89,4 +89,4 @@ module Eye::Dsl::Validation
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
-
end
|
92
|
+
end
|
data/lib/eye/group.rb
CHANGED
@@ -123,6 +123,10 @@ class Eye::Group
|
|
123
123
|
@chain_breaker = true
|
124
124
|
end
|
125
125
|
|
126
|
+
def freeze
|
127
|
+
async_schedule :freeze
|
128
|
+
end
|
129
|
+
|
126
130
|
def clear
|
127
131
|
@processes = Eye::Utils::AliveArray.new
|
128
132
|
end
|
@@ -137,7 +141,7 @@ private
|
|
137
141
|
info "send to all processes #{command} #{args.present? ? args*',' : nil}"
|
138
142
|
|
139
143
|
@processes.each do |process|
|
140
|
-
process.send_command(command, *args)
|
144
|
+
process.send_command(command, *args) unless process.skip_group_action?(command)
|
141
145
|
end
|
142
146
|
end
|
143
147
|
|
data/lib/eye/group/chain.rb
CHANGED
@@ -12,6 +12,11 @@ private
|
|
12
12
|
started_at = Time.now
|
13
13
|
|
14
14
|
@processes.each do | process |
|
15
|
+
if process.skip_group_action?(command)
|
16
|
+
@chain_processes_current = @chain_processes_current.to_i + 1
|
17
|
+
next
|
18
|
+
end
|
19
|
+
|
15
20
|
chain_schedule_process(process, type, command, *args)
|
16
21
|
|
17
22
|
@chain_processes_current = @chain_processes_current.to_i + 1
|
data/lib/eye/loader.rb
CHANGED
data/lib/eye/notify.rb
CHANGED
@@ -6,8 +6,9 @@ class Eye::Notify
|
|
6
6
|
|
7
7
|
autoload :Mail, 'eye/notify/mail'
|
8
8
|
autoload :Jabber, 'eye/notify/jabber'
|
9
|
+
autoload :Slack, 'eye/notify/slack'
|
9
10
|
|
10
|
-
TYPES = {:mail => 'Mail', :jabber => 'Jabber'}
|
11
|
+
TYPES = {:mail => 'Mail', :jabber => 'Jabber', :slack => 'Slack'}
|
11
12
|
|
12
13
|
def self.get_class(type)
|
13
14
|
klass = eval("Eye::Notify::#{TYPES[type]}") rescue nil
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'slack-notifier'
|
2
|
+
|
3
|
+
class Eye::Notify::Slack < Eye::Notify
|
4
|
+
|
5
|
+
# Eye.config do
|
6
|
+
# slack :webhook_url => "http://...", :channel => "#default", :username => "eye"
|
7
|
+
# contact :channel, :slack, "@channel"
|
8
|
+
# end
|
9
|
+
|
10
|
+
param :webhook_url, String, true
|
11
|
+
param :channel, String, nil, "#default"
|
12
|
+
param :username, String, nil, "eye"
|
13
|
+
|
14
|
+
param :icon, String
|
15
|
+
|
16
|
+
def execute
|
17
|
+
debug { "send slack #{[channel, username]} - #{[contact, message_body]}" }
|
18
|
+
|
19
|
+
options = {
|
20
|
+
channel: channel,
|
21
|
+
username: username
|
22
|
+
}
|
23
|
+
|
24
|
+
options[:icon_emoji] = icon if icon && icon.start_with?(':')
|
25
|
+
options[:icon_url] = icon if icon && icon.start_with?('http')
|
26
|
+
|
27
|
+
notifier = ::Slack::Notifier.new webhook_url, options
|
28
|
+
|
29
|
+
notifier.ping message_body
|
30
|
+
end
|
31
|
+
|
32
|
+
def message_body
|
33
|
+
payload = ''
|
34
|
+
payload << "#{contact}: *#{msg_host}* _#{msg_full_name}_ at #{Eye::Utils.human_time2(msg_at)}\n"
|
35
|
+
payload << "> #{msg_message}"
|
36
|
+
payload
|
37
|
+
end
|
38
|
+
end
|
data/lib/eye/process.rb
CHANGED
@@ -19,7 +19,7 @@ class Eye::Process
|
|
19
19
|
|
20
20
|
attr_accessor :pid, :parent_pid,
|
21
21
|
:watchers, :config, :states_history,
|
22
|
-
:children, :triggers, :name, :state_reason
|
22
|
+
:children, :triggers, :name, :state_reason
|
23
23
|
|
24
24
|
def initialize(config)
|
25
25
|
raise 'you must supply a pid_file location' unless config[:pid_file]
|
@@ -31,8 +31,6 @@ class Eye::Process
|
|
31
31
|
@triggers = []
|
32
32
|
@name = @config[:name]
|
33
33
|
|
34
|
-
@flapping_times = 0
|
35
|
-
|
36
34
|
@states_history = Eye::Process::StatesHistory.new(100)
|
37
35
|
@states_history << :unmonitored
|
38
36
|
|
data/lib/eye/process/config.rb
CHANGED
@@ -78,4 +78,15 @@ module Eye::Process::Config
|
|
78
78
|
!!self[:daemonize]
|
79
79
|
end
|
80
80
|
|
81
|
+
def skip_group_action?(action)
|
82
|
+
if sga = self[:skip_group_actions]
|
83
|
+
res = sga[action]
|
84
|
+
if res == true
|
85
|
+
res
|
86
|
+
elsif res.is_a?(Array)
|
87
|
+
res.include?(self.state_name)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
81
92
|
end
|
data/lib/eye/process/data.rb
CHANGED
@@ -40,7 +40,7 @@ module Eye::Process::Data
|
|
40
40
|
|
41
41
|
if @states_history
|
42
42
|
h.merge!( state_changed_at: @states_history.last_state_changed_at.to_i,
|
43
|
-
state_reason: @states_history.last_reason )
|
43
|
+
state_reason: @states_history.last_reason.to_s )
|
44
44
|
end
|
45
45
|
|
46
46
|
h.merge!(debug: debug_data) if debug
|
@@ -3,6 +3,11 @@ module Eye::Process::Scheduler
|
|
3
3
|
# ex: schedule :update_config, config, "reason: update_config"
|
4
4
|
def schedule(command, *args, &block)
|
5
5
|
if scheduler.alive?
|
6
|
+
if scheduler_freeze?
|
7
|
+
warn ":#{command} ignoring to schedule, because scheduler is freeze"
|
8
|
+
return
|
9
|
+
end
|
10
|
+
|
6
11
|
unless self.respond_to?(command, true)
|
7
12
|
warn ":#{command} scheduling is unsupported"
|
8
13
|
return
|
@@ -69,6 +74,18 @@ module Eye::Process::Scheduler
|
|
69
74
|
@schedule_history ||= Eye::Process::StatesHistory.new(50)
|
70
75
|
end
|
71
76
|
|
77
|
+
def scheduler_freeze
|
78
|
+
@scheduler_freeze = true
|
79
|
+
end
|
80
|
+
|
81
|
+
def scheduler_unfreeze
|
82
|
+
@scheduler_freeze = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def scheduler_freeze?
|
86
|
+
@scheduler_freeze
|
87
|
+
end
|
88
|
+
|
72
89
|
private
|
73
90
|
|
74
91
|
def remove_scheduler
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class Eye::Process::StatesHistory < Eye::Utils::Tail
|
2
|
-
|
3
2
|
def push(state, reason = nil, tm = Time.now)
|
4
3
|
super(state: state, at: tm.to_i, reason: reason)
|
5
4
|
end
|
@@ -26,41 +25,4 @@ class Eye::Process::StatesHistory < Eye::Utils::Tail
|
|
26
25
|
def last_state_changed_at
|
27
26
|
Time.at(last[:at])
|
28
27
|
end
|
29
|
-
|
30
|
-
def seq?(*seq)
|
31
|
-
str = states * ','
|
32
|
-
substr = seq.flatten * ','
|
33
|
-
str.include?(substr)
|
34
|
-
end
|
35
|
-
|
36
|
-
def end?(*seq)
|
37
|
-
str = states * ','
|
38
|
-
substr = seq.flatten * ','
|
39
|
-
str.end_with?(substr)
|
40
|
-
end
|
41
|
-
|
42
|
-
def any?(*seq)
|
43
|
-
states.any? do |st|
|
44
|
-
seq.flatten.include?(st)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def noone?(*seq)
|
49
|
-
!states.all? do |st|
|
50
|
-
seq.flatten.include?(st)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def all?(*seq)
|
55
|
-
states.all? do |st|
|
56
|
-
seq.flatten.include?(st)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def state_count(state)
|
61
|
-
states.count do |st|
|
62
|
-
st == state
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
28
|
+
end
|
data/lib/eye/process/trigger.rb
CHANGED
@@ -16,12 +16,20 @@ module Eye::Process::Trigger
|
|
16
16
|
self.triggers.each { |trigger| trigger.notify(transition, state_reason) }
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
# conditional start, used in triggers, to start only from unmonitored state, and only if special reason
|
20
|
+
def conditional_start
|
21
|
+
unless unmonitored?
|
22
|
+
warn "skip, because in state #{state_name}"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
previous_reason = state_reason
|
27
|
+
if last_scheduled_reason && previous_reason && last_scheduled_reason.class != previous_reason.class
|
28
|
+
warn "skip, last_scheduled_reason(#{last_scheduled_reason.inspect}) != previous_reason(#{previous_reason})"
|
29
|
+
return
|
30
|
+
end
|
22
31
|
|
23
|
-
|
24
|
-
self.flapping_times += 1
|
32
|
+
start
|
25
33
|
end
|
26
34
|
|
27
35
|
private
|
data/lib/eye/reason.rb
CHANGED
data/lib/eye/system_resources.rb
CHANGED
@@ -6,7 +6,9 @@ class Eye::SystemResources
|
|
6
6
|
class << self
|
7
7
|
|
8
8
|
def memory(pid)
|
9
|
-
cache.proc_mem(pid)
|
9
|
+
if mem = cache.proc_mem(pid)
|
10
|
+
mem.resident
|
11
|
+
end
|
10
12
|
end
|
11
13
|
|
12
14
|
def cpu(pid)
|
@@ -49,7 +51,7 @@ class Eye::SystemResources
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def cache
|
52
|
-
|
54
|
+
Celluloid::Actor[:system_resources_cache]
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
@@ -96,4 +98,6 @@ class Eye::SystemResources
|
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
101
|
+
# Setup global sigar singleton here
|
102
|
+
Cache.supervise_as(:system_resources_cache)
|
99
103
|
end
|
data/lib/eye/trigger.rb
CHANGED
@@ -6,9 +6,10 @@ class Eye::Trigger
|
|
6
6
|
autoload :StopChildren, 'eye/trigger/stop_children'
|
7
7
|
autoload :WaitDependency, 'eye/trigger/wait_dependency'
|
8
8
|
autoload :CheckDependency, 'eye/trigger/check_dependency'
|
9
|
+
autoload :StartingGuard, 'eye/trigger/starting_guard'
|
9
10
|
|
10
11
|
TYPES = {:flapping => 'Flapping', :transition => 'Transition', :stop_children => 'StopChildren',
|
11
|
-
:wait_dependency => 'WaitDependency', :check_dependency => 'CheckDependency'
|
12
|
+
:wait_dependency => 'WaitDependency', :check_dependency => 'CheckDependency', :starting_guard => 'StartingGuard'
|
12
13
|
}
|
13
14
|
|
14
15
|
attr_reader :message, :options, :process
|
@@ -99,6 +100,17 @@ class Eye::Trigger
|
|
99
100
|
process.instance_exec(&p) if process.alive?
|
100
101
|
end
|
101
102
|
|
103
|
+
def exec_proc(name = :do)
|
104
|
+
act = @options[name]
|
105
|
+
if act
|
106
|
+
res = instance_exec(&@options[name]) if act.is_a?(Proc)
|
107
|
+
res = send(act, process) if act.is_a?(Symbol)
|
108
|
+
res
|
109
|
+
else
|
110
|
+
true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
102
114
|
def defer(&block)
|
103
115
|
Celluloid::Future.new(&block).value
|
104
116
|
end
|
@@ -10,7 +10,7 @@ private
|
|
10
10
|
def check_dependency(to)
|
11
11
|
processes = names.map do |name|
|
12
12
|
Eye::Control.find_nearest_process(name, process.group_name_pure, process.app_name)
|
13
|
-
end.compact
|
13
|
+
end.compact.select { |p| p.state_name != :unmonitored }
|
14
14
|
return if processes.empty?
|
15
15
|
processes = Eye::Utils::AliveArray.new(processes)
|
16
16
|
|
data/lib/eye/trigger/flapping.rb
CHANGED
@@ -8,6 +8,11 @@ class Eye::Trigger::Flapping < Eye::Trigger
|
|
8
8
|
param :retry_in, [Float, Fixnum]
|
9
9
|
param :retry_times, [Fixnum]
|
10
10
|
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
@flapping_times = 0
|
14
|
+
end
|
15
|
+
|
11
16
|
def check(transition)
|
12
17
|
on_flapping if transition.event == :crashed && !good?
|
13
18
|
end
|
@@ -30,12 +35,13 @@ private
|
|
30
35
|
debug { 'flapping recognized!!!' }
|
31
36
|
|
32
37
|
process.notify :error, 'flapping!'
|
33
|
-
process.schedule :unmonitor, Eye::Reason.new(:flapping)
|
38
|
+
process.schedule :unmonitor, Eye::Reason::Flapping.new(:flapping)
|
34
39
|
|
35
40
|
return unless retry_in
|
36
|
-
return if retry_times &&
|
41
|
+
return if retry_times && @flapping_times >= retry_times
|
37
42
|
|
38
|
-
|
43
|
+
@flapping_times += 1
|
44
|
+
process.schedule_in(retry_in.to_f, :conditional_start, Eye::Reason::Flapping.new('retry start after flapping'))
|
39
45
|
end
|
40
46
|
|
41
47
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Eye::Trigger::StartingGuard < Eye::Trigger
|
2
|
+
|
3
|
+
# check that process ready to start or not
|
4
|
+
# by custom user condition
|
5
|
+
# if not, process switched to :unmonitored, and then retry to start after :every interval
|
6
|
+
#
|
7
|
+
# trigger :starting_guard, every: 10.seconds, should: ->{ `cat /tmp/bla` == "bla" }
|
8
|
+
|
9
|
+
param :every, [Float, Fixnum], false, 10
|
10
|
+
param :times, [Fixnum]
|
11
|
+
param :retry_in, [Float, Fixnum]
|
12
|
+
param :retry_times, [Fixnum]
|
13
|
+
param :should, [Proc, Symbol]
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super
|
17
|
+
|
18
|
+
@retry_count = 0
|
19
|
+
@reretry_count = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def check(transition)
|
23
|
+
check_start if transition.to_name == :starting
|
24
|
+
end
|
25
|
+
|
26
|
+
def check_start
|
27
|
+
@retry_count += 1
|
28
|
+
condition = defer { exec_proc(:should) }
|
29
|
+
|
30
|
+
if condition
|
31
|
+
info "ok, process ready to start #{condition.inspect}"
|
32
|
+
@retry_count = 0
|
33
|
+
@reretry_count = 0
|
34
|
+
return
|
35
|
+
else
|
36
|
+
info "false executed condition"
|
37
|
+
end
|
38
|
+
|
39
|
+
new_time = nil
|
40
|
+
if every
|
41
|
+
if times
|
42
|
+
if (@retry_count < times)
|
43
|
+
new_time = Time.now + every
|
44
|
+
process.schedule_in every, :conditional_start, Eye::Reason::StartingGuard.new("starting_guard, retry start")
|
45
|
+
else
|
46
|
+
@retry_count = 0
|
47
|
+
@reretry_count += 1
|
48
|
+
if retry_in && (!retry_times || (@reretry_count < retry_times))
|
49
|
+
new_time = Time.now + retry_in
|
50
|
+
process.schedule_in retry_in, :conditional_start, Eye::Reason::StartingGuard.new("starting_guard, reretry start")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
else
|
54
|
+
new_time = Time.now + every
|
55
|
+
process.schedule_in every, :conditional_start, Eye::Reason::StartingGuard.new("starting_guard, retry start")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
retry_msg = new_time ? ", retry at '#{Eye::Utils.human_time2(new_time.to_i)}'" : ''
|
60
|
+
process.switch :unmonitoring, Eye::Reason::StartingGuard.new("starting_guard, failed condition#{retry_msg}")
|
61
|
+
|
62
|
+
raise Eye::Process::StateError.new("starting_guard, refused to start")
|
63
|
+
end
|
64
|
+
end
|
@@ -5,11 +5,7 @@ class Eye::Trigger::Transition < Eye::Trigger
|
|
5
5
|
param :do, [Proc, Symbol]
|
6
6
|
|
7
7
|
def check(trans)
|
8
|
-
|
9
|
-
if act
|
10
|
-
instance_exec(&@options[:do]) if act.is_a?(Proc)
|
11
|
-
send(act, process) if act.is_a?(Symbol)
|
12
|
-
end
|
8
|
+
exec_proc :do
|
13
9
|
end
|
14
10
|
|
15
11
|
end
|
data/lib/eye/utils.rb
CHANGED
@@ -42,4 +42,17 @@ module Eye::Utils
|
|
42
42
|
Time.at(unix_time.to_i).strftime(DF)
|
43
43
|
end
|
44
44
|
|
45
|
+
def self.load_env(filename)
|
46
|
+
content = File.read(filename)
|
47
|
+
env_vars = content.split("\n")
|
48
|
+
h = {}
|
49
|
+
env_vars.each do |e|
|
50
|
+
e = e.gsub(/#.+$/, '').strip
|
51
|
+
next unless e.include?('=')
|
52
|
+
k, v = e.split('=', 2)
|
53
|
+
h[k] = v
|
54
|
+
end
|
55
|
+
h
|
56
|
+
end
|
57
|
+
|
45
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eye
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Makarchev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: celluloid
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.16.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.16.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: celluloid-io
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.16.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.16.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: state_machine
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -220,6 +220,20 @@ dependencies:
|
|
220
220
|
- - ">="
|
221
221
|
- !ruby/object:Gem::Version
|
222
222
|
version: '0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: slack-notifier
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
223
237
|
- !ruby/object:Gem::Dependency
|
224
238
|
name: coveralls
|
225
239
|
requirement: !ruby/object:Gem::Requirement
|
@@ -248,6 +262,34 @@ dependencies:
|
|
248
262
|
- - ">="
|
249
263
|
- !ruby/object:Gem::Version
|
250
264
|
version: 0.8.1
|
265
|
+
- !ruby/object:Gem::Dependency
|
266
|
+
name: parallel_tests
|
267
|
+
requirement: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - "<="
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: 1.3.1
|
272
|
+
type: :development
|
273
|
+
prerelease: false
|
274
|
+
version_requirements: !ruby/object:Gem::Requirement
|
275
|
+
requirements:
|
276
|
+
- - "<="
|
277
|
+
- !ruby/object:Gem::Version
|
278
|
+
version: 1.3.1
|
279
|
+
- !ruby/object:Gem::Dependency
|
280
|
+
name: parallel_split_test
|
281
|
+
requirement: !ruby/object:Gem::Requirement
|
282
|
+
requirements:
|
283
|
+
- - ">="
|
284
|
+
- !ruby/object:Gem::Version
|
285
|
+
version: '0'
|
286
|
+
type: :development
|
287
|
+
prerelease: false
|
288
|
+
version_requirements: !ruby/object:Gem::Requirement
|
289
|
+
requirements:
|
290
|
+
- - ">="
|
291
|
+
- !ruby/object:Gem::Version
|
292
|
+
version: '0'
|
251
293
|
description: Process monitoring tool. Inspired from Bluepill and God. Requires Ruby(MRI)
|
252
294
|
>= 1.9.3-p194. Uses Celluloid and Celluloid::IO.
|
253
295
|
email: eye-rb@googlegroups.com
|
@@ -339,6 +381,7 @@ files:
|
|
339
381
|
- lib/eye/notify.rb
|
340
382
|
- lib/eye/notify/jabber.rb
|
341
383
|
- lib/eye/notify/mail.rb
|
384
|
+
- lib/eye/notify/slack.rb
|
342
385
|
- lib/eye/process.rb
|
343
386
|
- lib/eye/process/children.rb
|
344
387
|
- lib/eye/process/commands.rb
|
@@ -362,6 +405,7 @@ files:
|
|
362
405
|
- lib/eye/trigger.rb
|
363
406
|
- lib/eye/trigger/check_dependency.rb
|
364
407
|
- lib/eye/trigger/flapping.rb
|
408
|
+
- lib/eye/trigger/starting_guard.rb
|
365
409
|
- lib/eye/trigger/stop_children.rb
|
366
410
|
- lib/eye/trigger/transition.rb
|
367
411
|
- lib/eye/trigger/wait_dependency.rb
|
@@ -393,7 +437,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
393
437
|
version: 1.3.6
|
394
438
|
requirements: []
|
395
439
|
rubyforge_project:
|
396
|
-
rubygems_version: 2.
|
440
|
+
rubygems_version: 2.4.5
|
397
441
|
signing_key:
|
398
442
|
specification_version: 4
|
399
443
|
summary: Process monitoring tool. Inspired from Bluepill and God. Requires Ruby(MRI)
|