eye 0.5.2 → 0.6

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 (60) hide show
  1. checksums.yaml +13 -5
  2. data/.travis.yml +1 -6
  3. data/CHANGES.md +12 -0
  4. data/README.md +5 -0
  5. data/Rakefile +4 -4
  6. data/bin/loader_eye +14 -3
  7. data/bin/runner +16 -0
  8. data/examples/dependency.eye +17 -0
  9. data/examples/plugin/README.md +15 -0
  10. data/examples/plugin/main.eye +15 -0
  11. data/examples/plugin/plugin.rb +63 -0
  12. data/examples/unicorn.eye +1 -1
  13. data/eye.gemspec +1 -2
  14. data/lib/eye.rb +1 -1
  15. data/lib/eye/checker.rb +16 -4
  16. data/lib/eye/checker/children_count.rb +44 -0
  17. data/lib/eye/checker/children_memory.rb +12 -0
  18. data/lib/eye/checker/socket.rb +9 -2
  19. data/lib/eye/child_process.rb +6 -2
  20. data/lib/eye/cli.rb +13 -2
  21. data/lib/eye/cli/commands.rb +2 -2
  22. data/lib/eye/cli/server.rb +11 -3
  23. data/lib/eye/config.rb +2 -2
  24. data/lib/eye/controller/commands.rb +29 -2
  25. data/lib/eye/controller/helpers.rb +31 -6
  26. data/lib/eye/controller/load.rb +5 -6
  27. data/lib/eye/controller/options.rb +1 -1
  28. data/lib/eye/controller/send_command.rb +0 -1
  29. data/lib/eye/dsl.rb +2 -1
  30. data/lib/eye/dsl/application_opts.rb +4 -7
  31. data/lib/eye/dsl/group_opts.rb +2 -1
  32. data/lib/eye/dsl/helpers.rb +9 -1
  33. data/lib/eye/dsl/main.rb +11 -5
  34. data/lib/eye/dsl/opts.rb +5 -22
  35. data/lib/eye/dsl/process_opts.rb +20 -2
  36. data/lib/eye/dsl/pure_opts.rb +1 -1
  37. data/lib/eye/dsl/validation.rb +17 -2
  38. data/lib/eye/local.rb +79 -50
  39. data/lib/eye/notify.rb +5 -3
  40. data/lib/eye/notify/mail.rb +6 -2
  41. data/lib/eye/process.rb +3 -1
  42. data/lib/eye/process/children.rb +1 -1
  43. data/lib/eye/process/commands.rb +17 -6
  44. data/lib/eye/process/config.rb +6 -1
  45. data/lib/eye/process/data.rb +20 -0
  46. data/lib/eye/process/monitor.rb +10 -4
  47. data/lib/eye/process/states.rb +5 -2
  48. data/lib/eye/process/states_history.rb +1 -1
  49. data/lib/eye/process/system.rb +6 -2
  50. data/lib/eye/process/trigger.rb +0 -1
  51. data/lib/eye/process/validate.rb +8 -6
  52. data/lib/eye/process/watchers.rb +1 -7
  53. data/lib/eye/system.rb +14 -11
  54. data/lib/eye/system_resources.rb +8 -0
  55. data/lib/eye/trigger.rb +12 -4
  56. data/lib/eye/trigger/check_dependency.rb +30 -0
  57. data/lib/eye/trigger/stop_children.rb +4 -1
  58. data/lib/eye/trigger/wait_dependency.rb +49 -0
  59. data/lib/eye/utils.rb +13 -0
  60. metadata +41 -45
data/lib/eye/cli.rb CHANGED
@@ -58,7 +58,7 @@ class Eye::Cli < Thor
58
58
 
59
59
  if options[:foreground]
60
60
  # in foreground we stop another server, and run just 1 current config version
61
- error!("foreground expected only one config") if configs.size != 1
61
+ error!("foreground expected only one config") if configs.size > 1
62
62
  server_start_foreground(configs.first)
63
63
 
64
64
  elsif server_started?
@@ -71,7 +71,15 @@ class Eye::Cli < Thor
71
71
  end
72
72
 
73
73
  desc "quit", "eye-daemon quit"
74
+ method_option :stop_all, :type => :boolean, :aliases => "-s"
75
+ method_option :timeout, :type => :string, :aliases => "-t", :default => "600"
74
76
  def quit
77
+ if options[:stop_all]
78
+ Eye::Local.client_timeout = options[:timeout].to_i
79
+ cmd(:stop_all, options[:timeout].to_i)
80
+ end
81
+
82
+ Eye::Local.client_timeout = 5
75
83
  res = _cmd(:quit)
76
84
 
77
85
  # if eye server got crazy, stop by force
@@ -80,7 +88,7 @@ class Eye::Cli < Thor
80
88
  # remove pid_file
81
89
  File.delete(Eye::Local.pid_path) if File.exists?(Eye::Local.pid_path)
82
90
 
83
- say "quit...", :yellow
91
+ say "Quit :(", :yellow
84
92
  end
85
93
 
86
94
  [:start, :stop, :restart, :unmonitor, :monitor, :delete, :match].each do |_cmd|
@@ -171,4 +179,7 @@ private
171
179
  end
172
180
  end
173
181
 
182
+ def self.exit_on_failure?
183
+ true
184
+ end
174
185
  end
@@ -42,9 +42,9 @@ private
42
42
  res[:backtrace].to_a.each{|line| say line, :red }
43
43
  else
44
44
  if opts[:syntax]
45
- say 'config ok!', :green if !res[:empty]
45
+ say 'Config ok!', :green if !res[:empty]
46
46
  else
47
- say 'config loaded!', :green if !res[:empty]
47
+ say 'Config loaded!', :green if !res[:empty]
48
48
  end
49
49
 
50
50
  if opts[:print_config]
@@ -30,8 +30,13 @@ private
30
30
  end
31
31
 
32
32
  args = []
33
- args += ['-c', conf] if conf
34
- args += ['-l', 'stdout']
33
+ args += ['--config', conf] if conf
34
+ args += ['--logger', 'stdout']
35
+ if Eye::Local.local_runner
36
+ args += ['--stop_all']
37
+ args += ['--dir', Eye::Local.dir]
38
+ args += ['--config', Eye::Local.eyefile] unless conf
39
+ end
35
40
 
36
41
  Process.exec(ruby_path, loader_path, *args)
37
42
  end
@@ -43,6 +48,8 @@ private
43
48
  ensure_stop_previous_server
44
49
 
45
50
  args = []
51
+ args += ['--dir', Eye::Local.dir] if Eye::Local.local_runner
52
+
46
53
  opts = {:out => '/dev/null', :err => '/dev/null', :in => '/dev/null',
47
54
  :chdir => '/', :pgroup => true}
48
55
 
@@ -55,8 +62,9 @@ private
55
62
  end
56
63
 
57
64
  configs.unshift(Eye::Local.eyeconfig) if File.exists?(Eye::Local.eyeconfig)
65
+ configs << Eye::Local.eyefile if Eye::Local.local_runner
58
66
 
59
- say 'eye started!', :green
67
+ say 'Eye started!', :green
60
68
 
61
69
  if !configs.empty?
62
70
  say_load_result cmd(:load, *configs)
data/lib/eye/config.rb CHANGED
@@ -21,7 +21,7 @@ class Eye::Config
21
21
  end
22
22
 
23
23
  # raise an error if config wrong
24
- def validate!
24
+ def validate!(localize = true)
25
25
  all_processes = processes
26
26
 
27
27
  # Check blank pid_files
@@ -55,7 +55,7 @@ class Eye::Config
55
55
 
56
56
  # validate processes with their own validate
57
57
  all_processes.each do |process_cfg|
58
- Eye::Process.validate process_cfg
58
+ Eye::Process.validate process_cfg, localize
59
59
  end
60
60
 
61
61
  # just to be sure ENV was not removed
@@ -1,8 +1,14 @@
1
1
  module Eye::Controller::Commands
2
2
 
3
+ NOT_IMPORTANT_COMMANDS = [:info_data, :short_data, :debug_data, :history_data, :ping,
4
+ :logger_dev, :match, :explain, :check]
5
+
3
6
  # Main method, answer for the client command
4
7
  def command(cmd, *args)
5
- debug "client command: #{cmd} #{args * ', '}"
8
+ msg = "command: #{cmd} #{args * ', '}"
9
+
10
+ log_str = "=> #{msg}"
11
+ NOT_IMPORTANT_COMMANDS.include?(cmd) ? debug(log_str) : info(log_str)
6
12
 
7
13
  start_at = Time.now
8
14
  cmd = cmd.to_sym
@@ -18,6 +24,8 @@ module Eye::Controller::Commands
18
24
  load(*args)
19
25
  when :quit
20
26
  quit
27
+ when :stop_all
28
+ stop_all(*args)
21
29
  when :check
22
30
  check(*args)
23
31
  when :explain
@@ -44,7 +52,9 @@ module Eye::Controller::Commands
44
52
  end
45
53
 
46
54
  GC.start
47
- info "client command: #{cmd} #{args * ', '} (#{Time.now - start_at}s)"
55
+
56
+ log_str = "<= #{msg} (#{Time.now - start_at}s)"
57
+ NOT_IMPORTANT_COMMANDS.include?(cmd) ? debug(log_str) : info(log_str)
48
58
 
49
59
  res
50
60
  end
@@ -58,4 +68,21 @@ private
58
68
  Eye::System.send_signal($$, :KILL)
59
69
  end
60
70
 
71
+ # stop all processes and wait
72
+ def stop_all(timeout = nil)
73
+ exclusive do
74
+ send_command :break_chain, 'all'
75
+ send_command :stop, 'all'
76
+ end
77
+
78
+ # wait until all processes goes to unmonitored
79
+ timeout ||= 100
80
+
81
+ all_processes.pmap do |p|
82
+ p.wait_for_condition(timeout, 0.3) do
83
+ p.state_name == :unmonitored
84
+ end
85
+ end
86
+ end
87
+
61
88
  end
@@ -2,8 +2,9 @@ module Eye::Controller::Helpers
2
2
 
3
3
  def set_proc_line
4
4
  str = Eye::PROCLINE
5
- str += " (#{@applications.map(&:name) * ', '})" if @applications.present?
6
- str += " [#{ENV['EYE_V']}]" if ENV['EYE_V']
5
+ str += " [#{@applications.map(&:name) * ', '}]" if @applications.present?
6
+ str += " (v #{ENV['EYE_V']})" if ENV['EYE_V']
7
+ str += " (in #{Eye::Local.dir})" if Eye::Local.local_runner
7
8
  $0 = str
8
9
  end
9
10
 
@@ -18,19 +19,43 @@ module Eye::Controller::Helpers
18
19
  end
19
20
 
20
21
  def process_by_name(name)
21
- all_processes.detect{|c| c.name == name}
22
+ name = name.to_s
23
+ all_processes.detect { |c| c.name == name }
22
24
  end
23
25
 
24
26
  def process_by_full_name(name)
25
- all_processes.detect{|c| c.full_name == name }
27
+ name = name.to_s
28
+ all_processes.detect { |c| c.full_name == name }
29
+ end
30
+
31
+ def find_nearest_process(name, group_name = nil, app_name = nil)
32
+ return process_by_full_name(name) if name.include?(':')
33
+
34
+ if app_name
35
+ app = application_by_name(app_name)
36
+ app.groups.each do |gr|
37
+ p = gr.processes.detect { |c| c.name == name }
38
+ return p if p
39
+ end
40
+ end
41
+
42
+ if group_name
43
+ gr = group_by_name(group_name)
44
+ p = gr.processes.detect { |c| c.name == name }
45
+ return p if p
46
+ end
47
+
48
+ process_by_name(name)
26
49
  end
27
50
 
28
51
  def group_by_name(name)
29
- all_groups.detect{|c| c.name == name}
52
+ name = name.to_s
53
+ all_groups.detect { |c| c.name == name }
30
54
  end
31
55
 
32
56
  def application_by_name(name)
33
- @applications.detect{|c| c.name == name}
57
+ name = name.to_s
58
+ @applications.detect { |c| c.name == name }
34
59
  end
35
60
 
36
61
  def all_processes
@@ -11,7 +11,7 @@ module Eye::Controller::Load
11
11
  def load(*args)
12
12
  h = args.extract_options!
13
13
  obj_strs = args.flatten
14
- info "loading: #{obj_strs}"
14
+ info "=> loading: #{obj_strs}"
15
15
 
16
16
  res = Hash.new
17
17
 
@@ -24,9 +24,8 @@ module Eye::Controller::Load
24
24
  end
25
25
 
26
26
  set_proc_line
27
- save_cache
28
27
 
29
- info "loaded: #{obj_strs}, selfpid <#{$$}>"
28
+ info "<= loading: #{obj_strs}, in: <#{$$}>"
30
29
 
31
30
  res
32
31
  end
@@ -34,7 +33,7 @@ module Eye::Controller::Load
34
33
  private
35
34
 
36
35
  # regexp for clean backtrace to show for user
37
- BT_REGX = %r[/lib/eye/|lib/celluloid|internal:prelude|logger.rb:|active_support/core_ext|shellwords.rb].freeze
36
+ BT_REGX = %r[/lib/eye/|lib/celluloid|internal:prelude|logger.rb:|active_support/core_ext|shellwords.rb|kernel/bootstrap].freeze
38
37
 
39
38
  def catch_load_error(filename = nil, &block)
40
39
  { :error => false, :config => yield }
@@ -46,7 +45,7 @@ private
46
45
 
47
46
  # filter backtrace for user output
48
47
  bt = (ex.backtrace || [])
49
- bt = bt.reject{|line| line.to_s =~ BT_REGX }
48
+ bt = bt.reject{|line| line.to_s =~ BT_REGX } unless ENV['EYE_FULL_BACKTRACE']
50
49
  error bt.join("\n")
51
50
 
52
51
  res = { :error => true, :message => ex.message }
@@ -84,7 +83,7 @@ private
84
83
  debug "parsing: #{filename}"
85
84
 
86
85
  cfg = Eye::Dsl.parse(nil, filename)
87
- @current_config.merge(cfg).validate! # just validate summary config here
86
+ @current_config.merge(cfg).validate!(false) # just validate summary config here
88
87
  Eye.parsed_config = nil # remove link on config, for better gc
89
88
  cfg
90
89
  end
@@ -12,7 +12,7 @@ module Eye::Controller::Options
12
12
  end
13
13
 
14
14
  def set_opt_http(opts = {})
15
- # stub!
15
+ warn "Warning, set http options not in reel-eye gem" if opts.present?
16
16
  end
17
17
 
18
18
  end
@@ -6,7 +6,6 @@ module Eye::Controller::SendCommand
6
6
  remove_object_from_tree(obj)
7
7
 
8
8
  set_proc_line
9
- save_cache
10
9
  end
11
10
 
12
11
  obj.send_command(command)
data/lib/eye/dsl.rb CHANGED
@@ -27,6 +27,7 @@ class Eye::Dsl
27
27
  def parse(content = nil, filename = nil)
28
28
  Eye.parsed_config = Eye::Config.new
29
29
  Eye.parsed_filename = filename
30
+ Eye.parsed_default_app = nil
30
31
 
31
32
  content = File.read(filename) if content.blank?
32
33
 
@@ -34,7 +35,7 @@ class Eye::Dsl
34
35
  Kernel.eval(content, Eye::BINDING, filename.to_s)
35
36
  end
36
37
 
37
- Eye.parsed_config.validate!
38
+ Eye.parsed_config.validate!(false)
38
39
  Eye.parsed_config
39
40
  end
40
41
 
@@ -17,14 +17,11 @@ class Eye::Dsl::ApplicationOpts < Eye::Dsl::Opts
17
17
  opts = Eye::Dsl::GroupOpts.new(name, self)
18
18
  opts.instance_eval(&block)
19
19
 
20
- if cfg = opts.config
21
- @config[:groups] ||= {}
20
+ @config[:groups] ||= {}
21
+ @config[:groups][name.to_s] ||= {}
22
22
 
23
- processes = cfg.delete(:processes) || {}
24
- @config[:groups][name.to_s] ||= {}
25
- @config[:groups][name.to_s].merge!(cfg)
26
- @config[:groups][name.to_s][:processes] ||= {}
27
- @config[:groups][name.to_s][:processes].merge!(processes)
23
+ if cfg = opts.config
24
+ Eye::Utils.deep_merge!(@config[:groups][name.to_s], cfg)
28
25
  end
29
26
 
30
27
  Eye::Dsl.debug "<= group #{name}"
@@ -18,7 +18,8 @@ class Eye::Dsl::GroupOpts < Eye::Dsl::Opts
18
18
  opts = Eye::Dsl::ProcessOpts.new(name, self)
19
19
  opts.instance_eval(&block)
20
20
  @config[:processes] ||= {}
21
- @config[:processes][name.to_s] = opts.config if opts.config
21
+ @config[:processes][name.to_s] ||= {}
22
+ Eye::Utils.deep_merge!(@config[:processes][name.to_s], opts.config) if opts.config
22
23
 
23
24
  Eye::Dsl.debug "<= process #{name}"
24
25
  opts
@@ -9,4 +9,12 @@ end
9
9
  # host name
10
10
  def hostname
11
11
  Eye::Local.host
12
- end
12
+ end
13
+
14
+ def example_process(proxy, name)
15
+ proxy.process(name) do
16
+ pid_file "/tmp/#{name}.pid"
17
+ start_command "sleep 100"
18
+ daemonize true
19
+ end
20
+ end
data/lib/eye/dsl/main.rb CHANGED
@@ -1,14 +1,20 @@
1
1
  module Eye::Dsl::Main
2
- attr_accessor :parsed_config, :parsed_filename
2
+ attr_accessor :parsed_config, :parsed_filename, :parsed_default_app
3
3
 
4
4
  def application(name, &block)
5
5
  Eye::Dsl.check_name(name)
6
+ name = name.to_s
6
7
 
7
8
  Eye::Dsl.debug "=> app: #{name}"
8
- opts = Eye::Dsl::ApplicationOpts.new(name)
9
- opts.instance_eval(&block)
10
9
 
11
- @parsed_config.applications[name.to_s] = opts.config if opts.config
10
+ if name == '__default__'
11
+ @parsed_default_app ||= Eye::Dsl::ApplicationOpts.new(name)
12
+ @parsed_default_app.instance_eval(&block)
13
+ else
14
+ opts = Eye::Dsl::ApplicationOpts.new(name, @parsed_default_app)
15
+ opts.instance_eval(&block)
16
+ @parsed_config.applications[name] = opts.config if opts.config
17
+ end
12
18
 
13
19
  Eye::Dsl.debug "<= app: #{name}"
14
20
  end
@@ -35,7 +41,7 @@ module Eye::Dsl::Main
35
41
 
36
42
  opts = Eye::Dsl::ConfigOpts.new
37
43
  opts.instance_eval(&block)
38
- @parsed_config.settings.merge!(opts.config)
44
+ Eye::Utils.deep_merge!(@parsed_config.settings, opts.config)
39
45
 
40
46
  Eye::Dsl.debug '<= config'
41
47
  end
data/lib/eye/dsl/opts.rb CHANGED
@@ -4,11 +4,12 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
4
4
  :stop_command, :restart_command, :uid, :gid ]
5
5
  create_options_methods(STR_OPTIONS, String)
6
6
 
7
- BOOL_OPTIONS = [ :daemonize, :keep_alive, :auto_start, :stop_on_delete, :clear_pid ]
7
+ BOOL_OPTIONS = [ :daemonize, :keep_alive, :auto_start, :stop_on_delete, :clear_pid, :preserve_fds, :use_leaf_child ]
8
8
  create_options_methods(BOOL_OPTIONS, [TrueClass, FalseClass])
9
9
 
10
10
  INTERVAL_OPTIONS = [ :check_alive_period, :start_timeout, :restart_timeout, :stop_timeout, :start_grace,
11
- :restart_grace, :stop_grace, :children_update_period, :restore_in ]
11
+ :restart_grace, :stop_grace, :children_update_period, :restore_in,
12
+ :auto_update_pidfile_grace, :revert_fuckup_pidfile_grace ]
12
13
  create_options_methods(INTERVAL_OPTIONS, [Fixnum, Float])
13
14
 
14
15
  create_options_methods([:environment], Hash)
@@ -23,7 +24,7 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
23
24
  @config[:group] = parent.name if parent.is_a?(Eye::Dsl::GroupOpts)
24
25
 
25
26
  # hack for full name
26
- @full_name = parent.full_name if @name == '__default__'
27
+ @full_name = parent.full_name if @name == '__default__' && parent.respond_to?(:full_name)
27
28
  end
28
29
 
29
30
  def checks(type, opts = {})
@@ -118,25 +119,7 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
118
119
  def scoped(&block)
119
120
  h = self.class.new(self.name, self)
120
121
  h.instance_eval(&block)
121
-
122
- groups = h.config.delete :groups
123
-
124
- if groups.present?
125
- config[:groups] ||= {}
126
- groups.each do |name, cfg|
127
- processes = cfg.delete(:processes) || {}
128
- config[:groups][name] ||= {}
129
- config[:groups][name].merge!(cfg)
130
- config[:groups][name][:processes] ||= {}
131
- config[:groups][name][:processes].merge!(processes)
132
- end
133
- end
134
-
135
- processes = h.config.delete :processes
136
- if processes.present?
137
- config[:processes] ||= {}
138
- config[:processes].merge!(processes)
139
- end
122
+ Eye::Utils.deep_merge!(config, h.config, [:groups, :processes])
140
123
  end
141
124
 
142
125
  # execute part of config on particular server
@@ -4,7 +4,7 @@ class Eye::Dsl::ProcessOpts < Eye::Dsl::Opts
4
4
  opts = Eye::Dsl::ChildProcessOpts.new
5
5
  opts.instance_eval(&block) if block
6
6
  @config[:monitor_children] ||= {}
7
- @config[:monitor_children].merge!(opts.config)
7
+ Eye::Utils.deep_merge!(@config[:monitor_children], opts.config)
8
8
  end
9
9
 
10
10
  alias xmonitor_children nop
@@ -15,4 +15,22 @@ class Eye::Dsl::ProcessOpts < Eye::Dsl::Opts
15
15
  alias app application
16
16
  alias group parent
17
17
 
18
- end
18
+ def depend_on(names, opts = {})
19
+ names = Array(names).map(&:to_s)
20
+ trigger("wait_dependency_#{unique_num}", {:names => names}.merge(opts))
21
+ nm = @config[:name]
22
+ names.each do |name|
23
+ parent.process(name) do
24
+ trigger("check_dependency_#{unique_num}", :names => [ nm ] )
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def unique_num
32
+ $unique_num ||= 0
33
+ $unique_num += 1
34
+ end
35
+
36
+ end