eye 0.5.2 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/.travis.yml +1 -6
- data/CHANGES.md +12 -0
- data/README.md +5 -0
- data/Rakefile +4 -4
- data/bin/loader_eye +14 -3
- data/bin/runner +16 -0
- data/examples/dependency.eye +17 -0
- data/examples/plugin/README.md +15 -0
- data/examples/plugin/main.eye +15 -0
- data/examples/plugin/plugin.rb +63 -0
- data/examples/unicorn.eye +1 -1
- data/eye.gemspec +1 -2
- data/lib/eye.rb +1 -1
- data/lib/eye/checker.rb +16 -4
- data/lib/eye/checker/children_count.rb +44 -0
- data/lib/eye/checker/children_memory.rb +12 -0
- data/lib/eye/checker/socket.rb +9 -2
- data/lib/eye/child_process.rb +6 -2
- data/lib/eye/cli.rb +13 -2
- data/lib/eye/cli/commands.rb +2 -2
- data/lib/eye/cli/server.rb +11 -3
- data/lib/eye/config.rb +2 -2
- data/lib/eye/controller/commands.rb +29 -2
- data/lib/eye/controller/helpers.rb +31 -6
- data/lib/eye/controller/load.rb +5 -6
- data/lib/eye/controller/options.rb +1 -1
- data/lib/eye/controller/send_command.rb +0 -1
- data/lib/eye/dsl.rb +2 -1
- data/lib/eye/dsl/application_opts.rb +4 -7
- data/lib/eye/dsl/group_opts.rb +2 -1
- data/lib/eye/dsl/helpers.rb +9 -1
- data/lib/eye/dsl/main.rb +11 -5
- data/lib/eye/dsl/opts.rb +5 -22
- data/lib/eye/dsl/process_opts.rb +20 -2
- data/lib/eye/dsl/pure_opts.rb +1 -1
- data/lib/eye/dsl/validation.rb +17 -2
- data/lib/eye/local.rb +79 -50
- data/lib/eye/notify.rb +5 -3
- data/lib/eye/notify/mail.rb +6 -2
- data/lib/eye/process.rb +3 -1
- data/lib/eye/process/children.rb +1 -1
- data/lib/eye/process/commands.rb +17 -6
- data/lib/eye/process/config.rb +6 -1
- data/lib/eye/process/data.rb +20 -0
- data/lib/eye/process/monitor.rb +10 -4
- data/lib/eye/process/states.rb +5 -2
- data/lib/eye/process/states_history.rb +1 -1
- data/lib/eye/process/system.rb +6 -2
- data/lib/eye/process/trigger.rb +0 -1
- data/lib/eye/process/validate.rb +8 -6
- data/lib/eye/process/watchers.rb +1 -7
- data/lib/eye/system.rb +14 -11
- data/lib/eye/system_resources.rb +8 -0
- data/lib/eye/trigger.rb +12 -4
- data/lib/eye/trigger/check_dependency.rb +30 -0
- data/lib/eye/trigger/stop_children.rb +4 -1
- data/lib/eye/trigger/wait_dependency.rb +49 -0
- data/lib/eye/utils.rb +13 -0
- metadata +41 -45
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YTRhNjdkYTZkYmFlMmJmNGJmMGUzNWM4N2ViZjAyOWZiODhiOThkNA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MzFiZDcwZjM4NTg4Y2QwNDI4NjgxZmU4MGQxZjEzMzQxYmJiZDY5Mw==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Zjk2MzM3ODlmMTA4ZTE4OTUzNTJkMTY3YzEzNTY5ZGM1ZmI4YWYzYjFiMjJk
|
10
|
+
N2RmMzJmNWE1ZDcyNzkyYmE1ZDhlNjM1ZTcxNzFmMmRlZmQ5YTVlNDE3NzNm
|
11
|
+
MGNlNmQwZDc1MzNjN2JlYzFjNWI5MDgyYWNmZDYyMjc0ZDRiNTE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MzRkYjE1M2FhN2Q4YmQyMDk0Y2Q3ZjYxN2Y2YmQwYTMwODM5YmJjMzI3Nzlh
|
14
|
+
NTFmMjA2MTc1OTk2ODA4Y2FkZjRjYTMwZGNlNmEyYWMzYTJlMTJiYmI4Y2Iw
|
15
|
+
YmQyODZjMzVlMzliZWNmNzVjNDAxZGU5YTM4YmVkNmRiMmJiY2M=
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
0.6
|
2
|
+
------
|
3
|
+
* add processes dependencies (#43)
|
4
|
+
* add eye-http gem (https://github.com/kostya/eye-http)
|
5
|
+
* add eye plugin example (https://github.com/kostya/eye/tree/master/examples/plugin)
|
6
|
+
* add quit option --stop_all (#39)
|
7
|
+
* add local eye runner (like foreman, used Eyefile)
|
8
|
+
* add use_leaf_child monitoring strategy (to daemonize sh -c '...') (788488a)
|
9
|
+
* add children_count, children_memory checks
|
10
|
+
* add dsl default application options (__default__)
|
11
|
+
* trusting external pid_file changes (#52)
|
12
|
+
|
1
13
|
0.5.2
|
2
14
|
-----
|
3
15
|
* rename dsl :childs_update_period to :children_update_period
|
data/README.md
CHANGED
@@ -185,6 +185,7 @@ Log tracing (tail and grep):
|
|
185
185
|
Quit monitoring:
|
186
186
|
|
187
187
|
$ eye q(uit)
|
188
|
+
$ eye q -s # stop all processes and quit
|
188
189
|
|
189
190
|
Interactive info:
|
190
191
|
|
@@ -204,4 +205,8 @@ Process states and events:
|
|
204
205
|
[![Eye](https://raw.github.com/kostya/stuff/master/eye/mprocess.png)](https://raw.github.com/kostya/stuff/master/eye/process.png)
|
205
206
|
|
206
207
|
|
208
|
+
EyeHttp Gem:
|
209
|
+
|
210
|
+
https://github.com/kostya/eye-http
|
211
|
+
|
207
212
|
Thanks `Bluepill` for the nice config ideas.
|
data/Rakefile
CHANGED
@@ -7,10 +7,10 @@ require 'coveralls/rake/task'
|
|
7
7
|
|
8
8
|
Coveralls::RakeTask.new
|
9
9
|
|
10
|
-
task :default => :
|
10
|
+
task :default => :pspec
|
11
11
|
|
12
|
-
task :
|
13
|
-
Rake::Task['parallel:spec'].invoke(ENV['N'] ||
|
12
|
+
task :pspec do
|
13
|
+
Rake::Task['parallel:spec'].invoke(ENV['N'] || 10)
|
14
14
|
end
|
15
15
|
|
16
16
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
@@ -26,7 +26,7 @@ task :env do
|
|
26
26
|
require 'bundler/setup'
|
27
27
|
require 'eye'
|
28
28
|
Eye::Controller
|
29
|
-
Eye::Process
|
29
|
+
Eye::Process
|
30
30
|
end
|
31
31
|
|
32
32
|
desc "graph"
|
data/bin/loader_eye
CHANGED
@@ -24,6 +24,15 @@ OptionParser.new do |opts|
|
|
24
24
|
options[:logger] = logger
|
25
25
|
end
|
26
26
|
|
27
|
+
opts.on( '-dr', '--dir DIR', 'Dir for local runner' ) do |dir|
|
28
|
+
Eye::Local.dir = dir
|
29
|
+
Eye::Local.local_runner = true
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on( '-st', '--stop_all', 'Stop all on exit' ) do |stop_all|
|
33
|
+
options[:stop_all] = true
|
34
|
+
end
|
35
|
+
|
27
36
|
opts.on( '-d', '--debug', 'debug info to logger' ) do
|
28
37
|
options[:debug] = true
|
29
38
|
end
|
@@ -52,8 +61,10 @@ Eye::Control.set_proc_line
|
|
52
61
|
|
53
62
|
server.async.run
|
54
63
|
|
55
|
-
trap("
|
56
|
-
trap("
|
57
|
-
trap("
|
64
|
+
trap("USR1") { Eye::Logger.reopen }
|
65
|
+
trap("USR2") { GC.start }
|
66
|
+
trap("INT") { exit }
|
67
|
+
|
68
|
+
at_exit { Eye::Control.command(:stop_all) } if options[:stop_all]
|
58
69
|
|
59
70
|
sleep
|
data/bin/runner
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib]))
|
3
|
+
require 'eye'
|
4
|
+
|
5
|
+
# Local version of eye
|
6
|
+
# which looking for Eyefile
|
7
|
+
# like foreman
|
8
|
+
|
9
|
+
unless Eye::Local.eyefile
|
10
|
+
puts "Not found Eyefile"
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
Eye::Local.dir = File.dirname(Eye::Local.eyefile)
|
15
|
+
Eye::Local.local_runner = true
|
16
|
+
Eye::Cli.start
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# process dependencies :b -> :a
|
2
|
+
|
3
|
+
Eye.app :dependency do
|
4
|
+
process(:a) do
|
5
|
+
start_command "sleep 100"
|
6
|
+
daemonize true
|
7
|
+
pid_file "/tmp/test_process_a.pid"
|
8
|
+
end
|
9
|
+
|
10
|
+
process(:b) do
|
11
|
+
start_command "sleep 100"
|
12
|
+
daemonize true
|
13
|
+
pid_file "/tmp/test_process_b.pid"
|
14
|
+
depend_on :a
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Eye Plugin Example
|
2
|
+
------------------
|
3
|
+
|
4
|
+
This plugin adds reactor which try to reads command from file "/tmp/cmd.txt" every 1.second (then execute it and delete file). Also plugin add trigger to save every process state transition into "/tmp/saver.log".
|
5
|
+
|
6
|
+
To test it:
|
7
|
+
|
8
|
+
bundle exec eye l examples/plugin/main.eye
|
9
|
+
tail -f /tmp/eye.log
|
10
|
+
tail -f /tmp/saver.log
|
11
|
+
echo 'restart' > /tmp/cmd.txt
|
12
|
+
|
13
|
+
Also, here http example of gem:
|
14
|
+
|
15
|
+
https://github.com/kostya/eye-http
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Eye.load('./plugin.rb')
|
2
|
+
|
3
|
+
Eye.config do
|
4
|
+
logger "/tmp/eye.log"
|
5
|
+
enable_reactor(1.second, "/tmp/cmd.txt")
|
6
|
+
enable_saver("/tmp/saver.log")
|
7
|
+
end
|
8
|
+
|
9
|
+
Eye.app :app do
|
10
|
+
process :process do
|
11
|
+
pid_file "/tmp/p.pid"
|
12
|
+
start_command "sleep 10"
|
13
|
+
daemonize true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class Reactor
|
2
|
+
include Celluloid
|
3
|
+
|
4
|
+
def initialize(interval, filename)
|
5
|
+
@interval = interval
|
6
|
+
@filename = filename
|
7
|
+
every(@interval) do
|
8
|
+
info "check file #{@filename}"
|
9
|
+
if cmd = read_file
|
10
|
+
execute_command cmd
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def read_file
|
16
|
+
if File.exists?(@filename)
|
17
|
+
cmd = File.read(@filename).chop
|
18
|
+
File.delete(@filename) rescue nil
|
19
|
+
cmd
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute_command(cmd)
|
24
|
+
Eye::Control.command(cmd, 'all') if %w{restart start stop}.include?(cmd)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Saver < Eye::Trigger::Custom
|
29
|
+
param :log_name, String, true
|
30
|
+
|
31
|
+
def check(trans)
|
32
|
+
tlogger.info "#{process.full_name} transition from #{trans.from_name} to #{trans.to_name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def tlogger
|
36
|
+
@tlogger ||= Logger.new(log_name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def reactor
|
41
|
+
Celluloid::Actor[:reactor]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Extend config options, add enable_reactor
|
45
|
+
class Eye::Dsl::ConfigOpts
|
46
|
+
def enable_reactor(*args)
|
47
|
+
@config[:reactor] = args
|
48
|
+
end
|
49
|
+
|
50
|
+
def enable_saver(save_log)
|
51
|
+
Eye.application '__default__' do
|
52
|
+
trigger :saver, :log_name => save_log
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# extend controller to execute method, and config loads
|
58
|
+
class Eye::Controller
|
59
|
+
def set_opt_reactor(args)
|
60
|
+
reactor.terminate if reactor
|
61
|
+
Celluloid::Actor[:reactor] = Reactor.supervise(*args)
|
62
|
+
end
|
63
|
+
end
|
data/examples/unicorn.eye
CHANGED
@@ -26,7 +26,7 @@ Eye.application "rails_unicorn" do
|
|
26
26
|
check :cpu, :every => 30, :below => 80, :times => 3
|
27
27
|
check :memory, :every => 30, :below => 150.megabytes, :times => [3,5]
|
28
28
|
|
29
|
-
start_timeout
|
29
|
+
start_timeout 100.seconds
|
30
30
|
restart_grace 30.seconds
|
31
31
|
|
32
32
|
monitor_children do
|
data/eye.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.version = Eye::VERSION
|
17
17
|
gem.license = "MIT"
|
18
18
|
|
19
|
-
gem.required_ruby_version = '>= 1.9.2'
|
19
|
+
gem.required_ruby_version = '>= 1.9.2'
|
20
20
|
gem.required_rubygems_version = '>= 1.3.6'
|
21
21
|
|
22
22
|
gem.add_dependency 'celluloid', '~> 0.15.0'
|
@@ -37,5 +37,4 @@ Gem::Specification.new do |gem|
|
|
37
37
|
gem.add_development_dependency 'xmpp4r'
|
38
38
|
gem.add_development_dependency 'coveralls'
|
39
39
|
gem.add_development_dependency 'simplecov', '>= 0.8.1'
|
40
|
-
gem.add_development_dependency 'parallel_tests'
|
41
40
|
end
|
data/lib/eye.rb
CHANGED
data/lib/eye/checker.rb
CHANGED
@@ -11,16 +11,19 @@ class Eye::Checker
|
|
11
11
|
autoload :Nop, 'eye/checker/nop'
|
12
12
|
autoload :Runtime, 'eye/checker/runtime'
|
13
13
|
autoload :Cputime, 'eye/checker/cputime'
|
14
|
+
autoload :ChildrenCount, 'eye/checker/children_count'
|
15
|
+
autoload :ChildrenMemory,'eye/checker/children_memory'
|
14
16
|
|
15
17
|
TYPES = {:memory => 'Memory', :cpu => 'Cpu', :http => 'Http',
|
16
18
|
:ctime => 'FileCTime', :fsize => 'FileSize', :file_touched => 'FileTouched',
|
17
|
-
:socket => 'Socket', :nop => 'Nop', :runtime => 'Runtime', :cputime => 'Cputime'
|
19
|
+
:socket => 'Socket', :nop => 'Nop', :runtime => 'Runtime', :cputime => 'Cputime',
|
20
|
+
:children_count => "ChildrenCount", :children_memory => "ChildrenMemory" }
|
18
21
|
|
19
22
|
attr_accessor :value, :values, :options, :pid, :type, :check_count, :process
|
20
23
|
|
21
24
|
param :every, [Fixnum, Float], false, 5
|
22
25
|
param :times, [Fixnum, Array], nil, 1
|
23
|
-
param :fires, [Symbol, Array], nil, nil, [:stop, :restart, :unmonitor, :
|
26
|
+
param :fires, [Symbol, Array], nil, nil, [:stop, :restart, :unmonitor, :start, :delete, :nothing, :notify]
|
24
27
|
param :initial_grace, [Fixnum, Float]
|
25
28
|
param :skip_initial_fails, [TrueClass, FalseClass]
|
26
29
|
|
@@ -37,7 +40,7 @@ class Eye::Checker
|
|
37
40
|
def self.get_class(type)
|
38
41
|
klass = eval("Eye::Checker::#{TYPES[type]}") rescue nil
|
39
42
|
raise "Unknown checker #{type}" unless klass
|
40
|
-
if deps = klass.
|
43
|
+
if deps = klass.requires
|
41
44
|
Array(deps).each { |d| require d }
|
42
45
|
end
|
43
46
|
klass
|
@@ -180,6 +183,15 @@ class Eye::Checker
|
|
180
183
|
process.instance_exec(&p) if process.alive?
|
181
184
|
end
|
182
185
|
|
186
|
+
def fire
|
187
|
+
actions = fires ? Array(fires) : [:restart]
|
188
|
+
process.notify :warn, "Bounded #{check_name}: #{last_human_values} send to #{actions}"
|
189
|
+
|
190
|
+
actions.each do |action|
|
191
|
+
process.schedule action, Eye::Reason.new("bounded #{check_name}")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
183
195
|
def defer(&block)
|
184
196
|
Celluloid::Future.new(&block).value
|
185
197
|
end
|
@@ -197,7 +209,7 @@ class Eye::Checker
|
|
197
209
|
Eye::Checker.const_set(name, base)
|
198
210
|
end
|
199
211
|
|
200
|
-
def self.
|
212
|
+
def self.requires
|
201
213
|
end
|
202
214
|
|
203
215
|
class CustomCell < Eye::Checker
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Eye::Checker::ChildrenCount < Eye::Checker::Measure
|
2
|
+
|
3
|
+
# check :children_count, :every => 30.seconds, :below => 10, :strategy => :kill_old
|
4
|
+
# monitor_children should be enabled
|
5
|
+
|
6
|
+
param :strategy, Symbol, nil, :restart, [:restart, :kill_old, :kill_new]
|
7
|
+
|
8
|
+
def get_value
|
9
|
+
process.children.size
|
10
|
+
end
|
11
|
+
|
12
|
+
def fire
|
13
|
+
if strategy == :restart
|
14
|
+
super
|
15
|
+
else
|
16
|
+
pids = ordered_by_date_children_pids
|
17
|
+
|
18
|
+
pids = if strategy == :kill_old
|
19
|
+
pids[0...-below]
|
20
|
+
else
|
21
|
+
pids[below..-1]
|
22
|
+
end
|
23
|
+
|
24
|
+
kill_pids(pids)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def kill_pids(pids)
|
31
|
+
info "killing pids: #{pids.inspect} for strategy: #{strategy}"
|
32
|
+
pids.each do |pid|
|
33
|
+
if child = process.children[pid]
|
34
|
+
child.schedule :stop, Eye::Reason.new("bounded #{check_name}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def ordered_by_date_children_pids
|
40
|
+
children = process.children.values
|
41
|
+
children.sort_by { |ch| Eye::SystemResources.start_time(ch.pid).to_i }.map &:pid
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Eye::Checker::ChildrenMemory < Eye::Checker::Measure
|
2
|
+
|
3
|
+
# check :children_memory, :every => 30.seconds, :below => 400.megabytes
|
4
|
+
# monitor_children should be enabled
|
5
|
+
|
6
|
+
def get_value
|
7
|
+
process.children.values.inject(0) do |sum, ch|
|
8
|
+
sum + Eye::SystemResources.memory(ch.pid).to_i
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
data/lib/eye/checker/socket.rb
CHANGED
@@ -18,7 +18,7 @@ class Eye::Checker::Socket < Eye::Checker::Defer
|
|
18
18
|
param :read_timeout, [Fixnum, Float]
|
19
19
|
param :send_data
|
20
20
|
param :expect_data, [String, Regexp, Proc]
|
21
|
-
param :protocol, [Symbol], nil, nil, [:default, :em_object]
|
21
|
+
param :protocol, [Symbol], nil, nil, [:default, :em_object, :raw]
|
22
22
|
|
23
23
|
def initialize(*args)
|
24
24
|
super
|
@@ -51,7 +51,11 @@ class Eye::Checker::Socket < Eye::Checker::Defer
|
|
51
51
|
{ :result => result }
|
52
52
|
end
|
53
53
|
rescue Timeout::Error
|
54
|
-
|
54
|
+
if protocol == :raw
|
55
|
+
return { :result => @buffer }
|
56
|
+
else
|
57
|
+
return { :exception => "ReadTimeout<#{@read_timeout}>" }
|
58
|
+
end
|
55
59
|
end
|
56
60
|
else
|
57
61
|
{ :result => :listen }
|
@@ -144,6 +148,9 @@ private
|
|
144
148
|
if content.present?
|
145
149
|
Marshal.load(content) rescue 'corrupted_marshal'
|
146
150
|
end
|
151
|
+
when :raw
|
152
|
+
@buffer = ''
|
153
|
+
loop { @buffer << socket.recv(1) }
|
147
154
|
else
|
148
155
|
socket.readline.chop
|
149
156
|
end
|
data/lib/eye/child_process.rb
CHANGED
@@ -26,10 +26,11 @@ class Eye::ChildProcess
|
|
26
26
|
|
27
27
|
attr_reader :pid, :name, :full_name, :config, :watchers
|
28
28
|
|
29
|
-
def initialize(pid, config = {}, logger_prefix = nil)
|
29
|
+
def initialize(pid, config = {}, logger_prefix = nil, parent_pid = nil)
|
30
30
|
raise 'Empty pid' unless pid
|
31
31
|
|
32
32
|
@pid = pid
|
33
|
+
@parent_pid = parent_pid
|
33
34
|
@config = prepare_config(config)
|
34
35
|
@name = "child-#{pid}"
|
35
36
|
@full_name = [logger_prefix, @name] * ':'
|
@@ -94,4 +95,7 @@ class Eye::ChildProcess
|
|
94
95
|
self_status_data(debug)
|
95
96
|
end
|
96
97
|
|
97
|
-
|
98
|
+
def prepare_command(command) # override
|
99
|
+
super.gsub('{PARENT_PID}', @parent_pid.to_s)
|
100
|
+
end
|
101
|
+
end
|