ace-eye 0.6.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.
- checksums.yaml +7 -0
- data/.gitignore +38 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/CHANGES.md +77 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +212 -0
- data/Rakefile +35 -0
- data/bin/eye +5 -0
- data/bin/loader_eye +72 -0
- data/bin/runner +16 -0
- data/examples/dependency.eye +17 -0
- data/examples/notify.eye +19 -0
- data/examples/plugin/README.md +15 -0
- data/examples/plugin/main.eye +15 -0
- data/examples/plugin/plugin.rb +63 -0
- data/examples/process_thin.rb +29 -0
- data/examples/processes/em.rb +57 -0
- data/examples/processes/forking.rb +20 -0
- data/examples/processes/sample.rb +144 -0
- data/examples/processes/thin.ru +12 -0
- data/examples/puma.eye +29 -0
- data/examples/rbenv.eye +11 -0
- data/examples/sidekiq.eye +23 -0
- data/examples/test.eye +87 -0
- data/examples/thin-farm.eye +30 -0
- data/examples/unicorn.eye +39 -0
- data/eye.gemspec +40 -0
- data/lib/eye.rb +28 -0
- data/lib/eye/application.rb +73 -0
- data/lib/eye/checker.rb +258 -0
- data/lib/eye/checker/children_count.rb +44 -0
- data/lib/eye/checker/children_memory.rb +12 -0
- data/lib/eye/checker/cpu.rb +17 -0
- data/lib/eye/checker/cputime.rb +13 -0
- data/lib/eye/checker/file_ctime.rb +24 -0
- data/lib/eye/checker/file_size.rb +34 -0
- data/lib/eye/checker/file_touched.rb +15 -0
- data/lib/eye/checker/http.rb +96 -0
- data/lib/eye/checker/memory.rb +17 -0
- data/lib/eye/checker/nop.rb +6 -0
- data/lib/eye/checker/runtime.rb +18 -0
- data/lib/eye/checker/socket.rb +159 -0
- data/lib/eye/child_process.rb +101 -0
- data/lib/eye/cli.rb +185 -0
- data/lib/eye/cli/commands.rb +78 -0
- data/lib/eye/cli/render.rb +130 -0
- data/lib/eye/cli/server.rb +93 -0
- data/lib/eye/client.rb +32 -0
- data/lib/eye/config.rb +91 -0
- data/lib/eye/control.rb +2 -0
- data/lib/eye/controller.rb +54 -0
- data/lib/eye/controller/commands.rb +88 -0
- data/lib/eye/controller/helpers.rb +101 -0
- data/lib/eye/controller/load.rb +224 -0
- data/lib/eye/controller/options.rb +18 -0
- data/lib/eye/controller/send_command.rb +177 -0
- data/lib/eye/controller/status.rb +72 -0
- data/lib/eye/dsl.rb +53 -0
- data/lib/eye/dsl/application_opts.rb +39 -0
- data/lib/eye/dsl/chain.rb +12 -0
- data/lib/eye/dsl/child_process_opts.rb +13 -0
- data/lib/eye/dsl/config_opts.rb +55 -0
- data/lib/eye/dsl/group_opts.rb +32 -0
- data/lib/eye/dsl/helpers.rb +20 -0
- data/lib/eye/dsl/main.rb +51 -0
- data/lib/eye/dsl/opts.rb +151 -0
- data/lib/eye/dsl/process_opts.rb +36 -0
- data/lib/eye/dsl/pure_opts.rb +121 -0
- data/lib/eye/dsl/validation.rb +88 -0
- data/lib/eye/group.rb +140 -0
- data/lib/eye/group/chain.rb +81 -0
- data/lib/eye/loader.rb +10 -0
- data/lib/eye/local.rb +100 -0
- data/lib/eye/logger.rb +104 -0
- data/lib/eye/notify.rb +118 -0
- data/lib/eye/notify/jabber.rb +30 -0
- data/lib/eye/notify/mail.rb +48 -0
- data/lib/eye/process.rb +85 -0
- data/lib/eye/process/children.rb +60 -0
- data/lib/eye/process/commands.rb +280 -0
- data/lib/eye/process/config.rb +81 -0
- data/lib/eye/process/controller.rb +73 -0
- data/lib/eye/process/data.rb +78 -0
- data/lib/eye/process/monitor.rb +108 -0
- data/lib/eye/process/notify.rb +32 -0
- data/lib/eye/process/scheduler.rb +82 -0
- data/lib/eye/process/states.rb +86 -0
- data/lib/eye/process/states_history.rb +66 -0
- data/lib/eye/process/system.rb +97 -0
- data/lib/eye/process/trigger.rb +34 -0
- data/lib/eye/process/validate.rb +33 -0
- data/lib/eye/process/watchers.rb +66 -0
- data/lib/eye/reason.rb +20 -0
- data/lib/eye/server.rb +60 -0
- data/lib/eye/sigar.rb +5 -0
- data/lib/eye/system.rb +139 -0
- data/lib/eye/system_resources.rb +99 -0
- data/lib/eye/trigger.rb +136 -0
- data/lib/eye/trigger/check_dependency.rb +30 -0
- data/lib/eye/trigger/flapping.rb +41 -0
- data/lib/eye/trigger/stop_children.rb +17 -0
- data/lib/eye/trigger/transition.rb +15 -0
- data/lib/eye/trigger/wait_dependency.rb +49 -0
- data/lib/eye/utils.rb +45 -0
- data/lib/eye/utils/alive_array.rb +57 -0
- data/lib/eye/utils/celluloid_chain.rb +71 -0
- data/lib/eye/utils/celluloid_klass.rb +5 -0
- data/lib/eye/utils/leak_19.rb +10 -0
- data/lib/eye/utils/mini_active_support.rb +111 -0
- data/lib/eye/utils/pmap.rb +7 -0
- data/lib/eye/utils/tail.rb +20 -0
- metadata +398 -0
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
|
data/examples/notify.eye
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Notify example
|
2
|
+
|
3
|
+
Eye.config do
|
4
|
+
mail :host => "mx.some.host", :port => 25, :domain => "some.host"
|
5
|
+
contact :errors, :mail, 'error@some.host'
|
6
|
+
contact :dev, :mail, 'dev@some.host'
|
7
|
+
end
|
8
|
+
|
9
|
+
Eye.application :some do
|
10
|
+
notify :errors
|
11
|
+
|
12
|
+
process :some_process do
|
13
|
+
notify :dev, :info
|
14
|
+
pid_file "1.pid"
|
15
|
+
|
16
|
+
#...
|
17
|
+
end
|
18
|
+
|
19
|
+
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
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
def thin(proxy, port)
|
3
|
+
name = "thin-#{port}"
|
4
|
+
|
5
|
+
opts = [
|
6
|
+
"-l thins.log",
|
7
|
+
"-p #{port}",
|
8
|
+
"-P #{name}.pid",
|
9
|
+
"-d",
|
10
|
+
"-R thin.ru",
|
11
|
+
"--tag #{proxy.app.name}.#{proxy.name}",
|
12
|
+
"-t 60",
|
13
|
+
"-e #{proxy.env["RAILS_ENV"]}",
|
14
|
+
"-c #{proxy.working_dir}",
|
15
|
+
"-a 127.0.0.1"
|
16
|
+
]
|
17
|
+
|
18
|
+
proxy.process(name) do
|
19
|
+
pid_file "#{name}.pid"
|
20
|
+
|
21
|
+
start_command "#{BUNDLE} exec thin start #{opts * ' '}"
|
22
|
+
stop_signals [:QUIT, 2.seconds, :TERM, 1.seconds, :KILL]
|
23
|
+
|
24
|
+
stdall "thin.stdall.log"
|
25
|
+
|
26
|
+
check :http, :url => "http://127.0.0.1:#{port}/hello", :pattern => /World/,
|
27
|
+
:every => 5.seconds, :times => [2, 3], :timeout => 1.second
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'eventmachine'
|
3
|
+
|
4
|
+
def answer(data)
|
5
|
+
case data
|
6
|
+
when 'ping' then "pong\n"
|
7
|
+
when 'bad' then "what\n"
|
8
|
+
when 'timeout' then sleep 5; "ok\n"
|
9
|
+
when 'exception' then raise 'haha'
|
10
|
+
when 'quit' then EM.stop
|
11
|
+
when 'big' then 'a' * 10_000_000
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Echo < EM::Connection
|
16
|
+
def post_init
|
17
|
+
puts "-- someone connected to the echo server!"
|
18
|
+
end
|
19
|
+
|
20
|
+
def receive_data data
|
21
|
+
puts "receive #{data.inspect} "
|
22
|
+
send_data(answer(data))
|
23
|
+
end
|
24
|
+
|
25
|
+
def unbind
|
26
|
+
puts "-- someone disconnected from the echo server!"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class EchoObj < EM::Connection
|
31
|
+
include EM::P::ObjectProtocol
|
32
|
+
|
33
|
+
def post_init
|
34
|
+
puts "-- someone connected to the echo server!"
|
35
|
+
end
|
36
|
+
|
37
|
+
def receive_object obj # {:command => 'ping'}
|
38
|
+
puts "receive #{obj.inspect}"
|
39
|
+
send_object(answer(obj[:command]).chop)
|
40
|
+
end
|
41
|
+
|
42
|
+
def unbind
|
43
|
+
puts "-- someone disconnected from the echo server!"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
trap "QUIT" do
|
48
|
+
puts "quit signal, stopping"
|
49
|
+
EM.stop
|
50
|
+
end
|
51
|
+
|
52
|
+
EM.run do
|
53
|
+
EM.start_server '127.0.0.1', 33221, Echo
|
54
|
+
EM.start_server '127.0.0.1', 33222, EchoObj
|
55
|
+
EM.start_server "/tmp/em_test_sock", nil, Echo
|
56
|
+
puts 'started'
|
57
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'forking'
|
3
|
+
|
4
|
+
root = File.expand_path(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
f = Forking.new(:name => 'forking', :working_dir => root,
|
7
|
+
:log_file => "#{root}/forking.log",
|
8
|
+
:pid_file => "#{root}/forking.pid", :sync_log => true)
|
9
|
+
|
10
|
+
3.times do |i|
|
11
|
+
f.spawn(:log_file => "#{root}/child#{i}.log", :sync_log => true) do
|
12
|
+
$0 = "forking child"
|
13
|
+
loop do
|
14
|
+
p "#{Time.now} - #{Time.now.to_f} - #{i} - tick"
|
15
|
+
sleep 0.1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
f.run!
|
@@ -0,0 +1,144 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
# This hash will hold all of the options
|
5
|
+
# parsed from the command-line by
|
6
|
+
# OptionParser.
|
7
|
+
options = {}
|
8
|
+
|
9
|
+
optparse = OptionParser.new do|opts|
|
10
|
+
# This displays the help screen, all programs are
|
11
|
+
# assumed to have this option.
|
12
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
13
|
+
puts opts
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on( '-p', '--pid FILE', 'pid_file' ) do |a|
|
18
|
+
options[:pid_file] = a
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on( '-l', '--log FILE', 'log_file' ) do |a|
|
22
|
+
options[:log_file] = a
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on( '-L', '--lock FILE', 'lock_file' ) do |a|
|
26
|
+
options[:lock_file] = a
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on( '-d', '--daemonize', 'Daemonize' ) do
|
30
|
+
options[:daemonize] = true
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on( '-s', '--daemonize_delay DELAY', 'Daemonized time' ) do |d|
|
34
|
+
options[:daemonize_delay] = d
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on( '-r', '--raise', 'Raised execution' ) do
|
38
|
+
options[:raise] = true
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on( '-w', '--watch_file FILE', 'Exit on touched file' ) do |w|
|
42
|
+
options[:watch_file] = w
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on( '-W', '--watch_file_delay DELAY', 'Exit on touched file, after delay' ) do |w|
|
46
|
+
options[:watch_file_delay] = w
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
optparse.parse!
|
52
|
+
|
53
|
+
module Sample
|
54
|
+
def puts(mes = "")
|
55
|
+
tm = Time.now
|
56
|
+
STDOUT.puts "#{tm.to_s} (#{tm.to_f}) - #{mes}"
|
57
|
+
STDOUT.flush
|
58
|
+
end
|
59
|
+
|
60
|
+
def daemonize(pid_file, log_file, daemonize_delay = 0)
|
61
|
+
puts "daemonize start #{pid_file}, #{log_file}, #{daemonize_delay}"
|
62
|
+
|
63
|
+
if daemonize_delay && daemonize_delay.to_f > 0
|
64
|
+
puts "daemonize delay start #{daemonize_delay}"
|
65
|
+
sleep daemonize_delay.to_f
|
66
|
+
puts "daemonize delay end"
|
67
|
+
end
|
68
|
+
|
69
|
+
daemon
|
70
|
+
STDOUT.reopen(log_file, "a")
|
71
|
+
STDERR.reopen(log_file, "a")
|
72
|
+
File.open(pid_file, 'w'){|f| f.write $$.to_s}
|
73
|
+
|
74
|
+
puts "daemonized"
|
75
|
+
end
|
76
|
+
|
77
|
+
def daemon
|
78
|
+
exit if fork # Parent exits, child continues.
|
79
|
+
Process.setsid # Become session leader.
|
80
|
+
exit if fork # Zap session leader. See [1].
|
81
|
+
|
82
|
+
STDIN.reopen "/dev/null" # Free file descriptors and
|
83
|
+
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
|
84
|
+
STDERR.reopen '/dev/null', 'a'
|
85
|
+
return 0
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
extend Sample
|
90
|
+
|
91
|
+
if options[:daemonize]
|
92
|
+
daemonize(options[:pid_file], options[:log_file], options[:daemonize_delay])
|
93
|
+
end
|
94
|
+
|
95
|
+
puts "Started #{ARGV.inspect}, #{options.inspect}, #{ENV["ENV1"]}"
|
96
|
+
|
97
|
+
if options[:lock_file]
|
98
|
+
if File.exists?(options[:lock_file])
|
99
|
+
puts "Lock file exists, exiting"
|
100
|
+
exit 1
|
101
|
+
else
|
102
|
+
File.open(options[:lock_file], 'w'){|f| f.write $$ }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if options[:raise]
|
107
|
+
puts "Raised"
|
108
|
+
File.unlink(options[:lock_file]) if options[:lock_file]
|
109
|
+
exit 1
|
110
|
+
end
|
111
|
+
|
112
|
+
trap("USR1") do
|
113
|
+
puts "USR1 signal!"
|
114
|
+
end
|
115
|
+
|
116
|
+
trap("USR2") do
|
117
|
+
puts "USR2 start memory leak"
|
118
|
+
$ar = []
|
119
|
+
300_000.times{|i| $ar << "memory leak #{i}" * 10}
|
120
|
+
end
|
121
|
+
|
122
|
+
loop do
|
123
|
+
sleep 0.1
|
124
|
+
puts "tick"
|
125
|
+
|
126
|
+
if options[:watch_file]
|
127
|
+
if File.exists?(options[:watch_file])
|
128
|
+
puts "watch file finded"
|
129
|
+
File.unlink(options[:watch_file])
|
130
|
+
|
131
|
+
if options[:watch_file_delay]
|
132
|
+
puts "watch_file delay start"
|
133
|
+
sleep options[:watch_file_delay].to_f
|
134
|
+
puts "watch_file delay end"
|
135
|
+
end
|
136
|
+
|
137
|
+
break
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
puts "exit"
|
143
|
+
File.unlink(options[:lock_file]) if options[:lock_file]
|
144
|
+
exit 0
|
data/examples/puma.eye
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
BUNDLE = 'bundle'
|
2
|
+
RAILS_ENV = 'production'
|
3
|
+
ROOT = File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
|
4
|
+
|
5
|
+
Eye.config do
|
6
|
+
logger "#{ROOT}/eye.log"
|
7
|
+
end
|
8
|
+
|
9
|
+
Eye.application :puma do
|
10
|
+
env 'RAILS_ENV' => RAILS_ENV
|
11
|
+
working_dir ROOT
|
12
|
+
trigger :flapping, :times => 10, :within => 1.minute
|
13
|
+
|
14
|
+
process :puma do
|
15
|
+
daemonize true
|
16
|
+
pid_file "puma.pid"
|
17
|
+
stdall "puma.log"
|
18
|
+
|
19
|
+
start_command "#{BUNDLE} exec puma --port 33280 --environment #{RAILS_ENV} thin.ru"
|
20
|
+
stop_signals [:TERM, 5.seconds, :KILL]
|
21
|
+
restart_command "kill -USR2 {PID}"
|
22
|
+
|
23
|
+
restart_grace 10.seconds # just sleep this until process get up status
|
24
|
+
# (maybe enought to puma soft restart)
|
25
|
+
|
26
|
+
check :cpu, :every => 30, :below => 80, :times => 3
|
27
|
+
check :memory, :every => 30, :below => 70.megabytes, :times => [3,5]
|
28
|
+
end
|
29
|
+
end
|