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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +38 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/CHANGES.md +77 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE +22 -0
  8. data/README.md +212 -0
  9. data/Rakefile +35 -0
  10. data/bin/eye +5 -0
  11. data/bin/loader_eye +72 -0
  12. data/bin/runner +16 -0
  13. data/examples/dependency.eye +17 -0
  14. data/examples/notify.eye +19 -0
  15. data/examples/plugin/README.md +15 -0
  16. data/examples/plugin/main.eye +15 -0
  17. data/examples/plugin/plugin.rb +63 -0
  18. data/examples/process_thin.rb +29 -0
  19. data/examples/processes/em.rb +57 -0
  20. data/examples/processes/forking.rb +20 -0
  21. data/examples/processes/sample.rb +144 -0
  22. data/examples/processes/thin.ru +12 -0
  23. data/examples/puma.eye +29 -0
  24. data/examples/rbenv.eye +11 -0
  25. data/examples/sidekiq.eye +23 -0
  26. data/examples/test.eye +87 -0
  27. data/examples/thin-farm.eye +30 -0
  28. data/examples/unicorn.eye +39 -0
  29. data/eye.gemspec +40 -0
  30. data/lib/eye.rb +28 -0
  31. data/lib/eye/application.rb +73 -0
  32. data/lib/eye/checker.rb +258 -0
  33. data/lib/eye/checker/children_count.rb +44 -0
  34. data/lib/eye/checker/children_memory.rb +12 -0
  35. data/lib/eye/checker/cpu.rb +17 -0
  36. data/lib/eye/checker/cputime.rb +13 -0
  37. data/lib/eye/checker/file_ctime.rb +24 -0
  38. data/lib/eye/checker/file_size.rb +34 -0
  39. data/lib/eye/checker/file_touched.rb +15 -0
  40. data/lib/eye/checker/http.rb +96 -0
  41. data/lib/eye/checker/memory.rb +17 -0
  42. data/lib/eye/checker/nop.rb +6 -0
  43. data/lib/eye/checker/runtime.rb +18 -0
  44. data/lib/eye/checker/socket.rb +159 -0
  45. data/lib/eye/child_process.rb +101 -0
  46. data/lib/eye/cli.rb +185 -0
  47. data/lib/eye/cli/commands.rb +78 -0
  48. data/lib/eye/cli/render.rb +130 -0
  49. data/lib/eye/cli/server.rb +93 -0
  50. data/lib/eye/client.rb +32 -0
  51. data/lib/eye/config.rb +91 -0
  52. data/lib/eye/control.rb +2 -0
  53. data/lib/eye/controller.rb +54 -0
  54. data/lib/eye/controller/commands.rb +88 -0
  55. data/lib/eye/controller/helpers.rb +101 -0
  56. data/lib/eye/controller/load.rb +224 -0
  57. data/lib/eye/controller/options.rb +18 -0
  58. data/lib/eye/controller/send_command.rb +177 -0
  59. data/lib/eye/controller/status.rb +72 -0
  60. data/lib/eye/dsl.rb +53 -0
  61. data/lib/eye/dsl/application_opts.rb +39 -0
  62. data/lib/eye/dsl/chain.rb +12 -0
  63. data/lib/eye/dsl/child_process_opts.rb +13 -0
  64. data/lib/eye/dsl/config_opts.rb +55 -0
  65. data/lib/eye/dsl/group_opts.rb +32 -0
  66. data/lib/eye/dsl/helpers.rb +20 -0
  67. data/lib/eye/dsl/main.rb +51 -0
  68. data/lib/eye/dsl/opts.rb +151 -0
  69. data/lib/eye/dsl/process_opts.rb +36 -0
  70. data/lib/eye/dsl/pure_opts.rb +121 -0
  71. data/lib/eye/dsl/validation.rb +88 -0
  72. data/lib/eye/group.rb +140 -0
  73. data/lib/eye/group/chain.rb +81 -0
  74. data/lib/eye/loader.rb +10 -0
  75. data/lib/eye/local.rb +100 -0
  76. data/lib/eye/logger.rb +104 -0
  77. data/lib/eye/notify.rb +118 -0
  78. data/lib/eye/notify/jabber.rb +30 -0
  79. data/lib/eye/notify/mail.rb +48 -0
  80. data/lib/eye/process.rb +85 -0
  81. data/lib/eye/process/children.rb +60 -0
  82. data/lib/eye/process/commands.rb +280 -0
  83. data/lib/eye/process/config.rb +81 -0
  84. data/lib/eye/process/controller.rb +73 -0
  85. data/lib/eye/process/data.rb +78 -0
  86. data/lib/eye/process/monitor.rb +108 -0
  87. data/lib/eye/process/notify.rb +32 -0
  88. data/lib/eye/process/scheduler.rb +82 -0
  89. data/lib/eye/process/states.rb +86 -0
  90. data/lib/eye/process/states_history.rb +66 -0
  91. data/lib/eye/process/system.rb +97 -0
  92. data/lib/eye/process/trigger.rb +34 -0
  93. data/lib/eye/process/validate.rb +33 -0
  94. data/lib/eye/process/watchers.rb +66 -0
  95. data/lib/eye/reason.rb +20 -0
  96. data/lib/eye/server.rb +60 -0
  97. data/lib/eye/sigar.rb +5 -0
  98. data/lib/eye/system.rb +139 -0
  99. data/lib/eye/system_resources.rb +99 -0
  100. data/lib/eye/trigger.rb +136 -0
  101. data/lib/eye/trigger/check_dependency.rb +30 -0
  102. data/lib/eye/trigger/flapping.rb +41 -0
  103. data/lib/eye/trigger/stop_children.rb +17 -0
  104. data/lib/eye/trigger/transition.rb +15 -0
  105. data/lib/eye/trigger/wait_dependency.rb +49 -0
  106. data/lib/eye/utils.rb +45 -0
  107. data/lib/eye/utils/alive_array.rb +57 -0
  108. data/lib/eye/utils/celluloid_chain.rb +71 -0
  109. data/lib/eye/utils/celluloid_klass.rb +5 -0
  110. data/lib/eye/utils/leak_19.rb +10 -0
  111. data/lib/eye/utils/mini_active_support.rb +111 -0
  112. data/lib/eye/utils/pmap.rb +7 -0
  113. data/lib/eye/utils/tail.rb +20 -0
  114. metadata +398 -0
@@ -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,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
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+ require 'sinatra'
3
+
4
+ class Test < Sinatra::Base
5
+
6
+ get '/hello' do
7
+ sleep 0.5
8
+ "Hello World!"
9
+ end
10
+ end
11
+
12
+ run Test.new
@@ -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