eye 0.8.1 → 0.9.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +21 -2
  4. data/.travis.yml +2 -1
  5. data/Gemfile +3 -0
  6. data/LICENSE +1 -1
  7. data/README.md +1 -1
  8. data/bin/loader_eye +1 -1
  9. data/examples/delayed_job.eye +2 -2
  10. data/examples/processes/sample.rb +1 -1
  11. data/examples/puma.eye +1 -1
  12. data/examples/rbenv.eye +1 -1
  13. data/examples/sidekiq.eye +1 -1
  14. data/examples/test.eye +1 -1
  15. data/examples/thin-farm.eye +1 -1
  16. data/examples/unicorn.eye +1 -1
  17. data/eye.gemspec +2 -2
  18. data/lib/eye.rb +2 -3
  19. data/lib/eye/application.rb +3 -6
  20. data/lib/eye/checker.rb +4 -3
  21. data/lib/eye/checker/children_count.rb +3 -3
  22. data/lib/eye/checker/socket.rb +7 -12
  23. data/lib/eye/child_process.rb +5 -7
  24. data/lib/eye/cli.rb +6 -4
  25. data/lib/eye/cli/commands.rb +1 -1
  26. data/lib/eye/cli/render.rb +6 -5
  27. data/lib/eye/client.rb +9 -4
  28. data/lib/eye/controller.rb +2 -2
  29. data/lib/eye/controller/{send_command.rb → apply.rb} +25 -32
  30. data/lib/eye/controller/commands.rb +13 -10
  31. data/lib/eye/controller/load.rb +49 -38
  32. data/lib/eye/controller/status.rb +2 -2
  33. data/lib/eye/dsl.rb +1 -1
  34. data/lib/eye/dsl/application_opts.rb +2 -2
  35. data/lib/eye/dsl/child_process_opts.rb +1 -1
  36. data/lib/eye/dsl/config_opts.rb +1 -1
  37. data/lib/eye/dsl/group_opts.rb +3 -3
  38. data/lib/eye/dsl/main.rb +3 -3
  39. data/lib/eye/dsl/opts.rb +17 -21
  40. data/lib/eye/dsl/process_opts.rb +3 -3
  41. data/lib/eye/dsl/validation.rb +2 -2
  42. data/lib/eye/group.rb +8 -114
  43. data/lib/eye/group/call.rb +73 -0
  44. data/lib/eye/group/chain.rb +19 -17
  45. data/lib/eye/group/data.rb +40 -0
  46. data/lib/eye/loader.rb +1 -1
  47. data/lib/eye/logger.rb +4 -4
  48. data/lib/eye/process.rb +2 -0
  49. data/lib/eye/process/commands.rb +11 -19
  50. data/lib/eye/process/config.rb +2 -1
  51. data/lib/eye/process/controller.rb +5 -12
  52. data/lib/eye/process/data.rb +11 -3
  53. data/lib/eye/process/monitor.rb +5 -5
  54. data/lib/eye/process/notify.rb +1 -1
  55. data/lib/eye/process/scheduler.rb +118 -63
  56. data/lib/eye/process/states.rb +10 -9
  57. data/lib/eye/process/states_history.rb +1 -1
  58. data/lib/eye/process/system.rb +1 -1
  59. data/lib/eye/process/trigger.rb +5 -4
  60. data/lib/eye/process/validate.rb +1 -1
  61. data/lib/eye/server.rb +22 -9
  62. data/lib/eye/trigger.rb +4 -7
  63. data/lib/eye/trigger/check_dependency.rb +1 -1
  64. data/lib/eye/trigger/flapping.rb +8 -10
  65. data/lib/eye/trigger/starting_guard.rb +7 -4
  66. data/lib/eye/trigger/stop_children.rb +1 -1
  67. data/lib/eye/trigger/wait_dependency.rb +2 -2
  68. data/lib/eye/utils.rb +19 -9
  69. metadata +10 -10
  70. data/lib/eye/reason.rb +0 -26
  71. data/lib/eye/utils/celluloid_chain.rb +0 -73
@@ -19,14 +19,14 @@ class Eye::Controller
19
19
  autoload :Helpers, 'eye/controller/helpers'
20
20
  autoload :Commands, 'eye/controller/commands'
21
21
  autoload :Status, 'eye/controller/status'
22
- autoload :SendCommand, 'eye/controller/send_command'
22
+ autoload :Apply, 'eye/controller/apply'
23
23
  autoload :Options, 'eye/controller/options'
24
24
 
25
25
  include Eye::Controller::Load
26
26
  include Eye::Controller::Helpers
27
27
  include Eye::Controller::Commands
28
28
  include Eye::Controller::Status
29
- include Eye::Controller::SendCommand
29
+ include Eye::Controller::Apply
30
30
  include Eye::Controller::Options
31
31
 
32
32
  attr_reader :applications, :current_config
@@ -1,45 +1,40 @@
1
- module Eye::Controller::SendCommand
1
+ module Eye::Controller::Apply
2
2
 
3
- def send_command(command, *args)
4
- matched_objects(*args) do |obj|
5
- if command.to_sym == :delete
3
+ def apply(masks, call)
4
+ res = matched_objects(*masks) do |obj|
5
+ if call[:command].to_sym == :delete
6
6
  remove_object_from_tree(obj)
7
-
8
7
  set_proc_line
9
8
  end
10
-
11
- obj.send_command(command)
12
9
  end
10
+
11
+ objs = res.delete(:objects)
12
+ async.apply_to_objects(objs, call) if objs
13
+ res
13
14
  end
14
15
 
15
16
  def match(*args)
16
17
  matched_objects(*args)
17
18
  end
18
19
 
19
- def signal(signal, *args)
20
- matched_objects(*args) do |obj|
21
- obj.send_command :signal, signal || 0
22
- end
23
- end
20
+ private
24
21
 
25
- def user_command(cmd, *args)
26
- matched_objects(*args) do |obj|
27
- obj.send_command :user_command, cmd
22
+ def apply_to_objects(objs, call)
23
+ # TODO: if signal, create multiple signals?
24
+ objs.each do |obj|
25
+ obj.send_call(call)
28
26
  end
29
27
  end
30
28
 
31
- private
32
-
33
- class Error < Exception; end
29
+ class Error < RuntimeError; end
34
30
 
35
31
  def matched_objects(*args, &block)
36
32
  objs = find_objects(*args)
37
33
  res = objs.map(&:full_name)
38
34
  objs.each { |obj| block[obj] } if block
39
- { result: res }
35
+ { result: res, objects: objs }
40
36
 
41
37
  rescue Error => ex
42
- log_ex(ex)
43
38
  { error: ex.message }
44
39
 
45
40
  rescue Celluloid::DeadActorError => ex
@@ -69,17 +64,15 @@ private
69
64
  # find object to action, restart ... (app, group or process)
70
65
  # nil if not found
71
66
  def find_objects(*args)
67
+ # TODO, why h? for what?
72
68
  h = args.extract_options!
73
69
  obj_strs = args
74
70
 
75
71
  return [] if obj_strs.blank?
76
72
 
77
73
  if obj_strs.size == 1 && (obj_strs[0].to_s.strip == 'all' || obj_strs[0].to_s.strip == '*')
78
- if h[:application]
79
- return @applications.select { |app| app.name == h[:application] }
80
- else
81
- return @applications.dup
82
- end
74
+ return @applications.dup unless h[:application]
75
+ return @applications.select { |app| app.name == h[:application] }
83
76
  end
84
77
 
85
78
  res = Eye::Utils::AliveArray.new
@@ -127,7 +120,7 @@ private
127
120
  end
128
121
  end
129
122
 
130
- return apps if apps.size > 0
123
+ return apps unless apps.empty?
131
124
 
132
125
  if !mask.start_with?('*') && objs.map(&:app_name).uniq.size > 1
133
126
  raise Error, "cannot match targets from different applications: #{res.map(&:full_name)}"
@@ -156,12 +149,12 @@ private
156
149
  res << p if p.name =~ r || p.full_name =~ r
157
150
 
158
151
  # children matching
159
- if (ch = p.children) && (!ch.empty?)
160
- ch.values.each do |ch|
161
- name = ch.name rescue ''
162
- full_name = ch.full_name rescue ''
163
- res << ch if name =~ r || full_name =~ r
164
- end
152
+ ch = p.children
153
+ next if ch.empty?
154
+ ch.values.each do |child|
155
+ name = child.name rescue ''
156
+ full_name = child.full_name rescue ''
157
+ res << child if name =~ r || full_name =~ r
165
158
  end
166
159
  end
167
160
  end
@@ -1,10 +1,11 @@
1
1
  module Eye::Controller::Commands
2
2
 
3
3
  NOT_IMPORTANT_COMMANDS = [:info_data, :short_data, :debug_data, :history_data, :ping,
4
- :logger_dev, :match, :explain, :check]
4
+ :logger_dev, :match, :explain, :check].freeze
5
5
 
6
6
  # Main method, answer for the client command
7
7
  def command(cmd, *args)
8
+ opts = args.extract_options!
8
9
  msg = "command: #{cmd} #{args * ', '}"
9
10
 
10
11
  log_str = "=> #{msg}"
@@ -14,14 +15,16 @@ module Eye::Controller::Commands
14
15
  cmd = cmd.to_sym
15
16
 
16
17
  res = case cmd
18
+
19
+ # scheduled command
17
20
  when :start, :stop, :restart, :unmonitor, :monitor, :break_chain
18
- send_command(cmd, *args)
21
+ apply(args, command: cmd, signal: opts[:signal])
19
22
  when :delete
20
- exclusive { send_command(cmd, *args) }
21
- when :signal
22
- signal(*args)
23
- when :user_command
24
- user_command(*args)
23
+ exclusive { apply(args, command: cmd, signal: opts[:signal]) }
24
+ when :signal, :user_command
25
+ apply(args[1..-1], command: cmd, args: args[0...1], signal: opts[:signal])
26
+
27
+ # inline command
25
28
  when :load
26
29
  exclusive { load(*args) }
27
30
  when :quit
@@ -72,10 +75,10 @@ private
72
75
 
73
76
  # stop all processes and wait
74
77
  def stop_all(timeout = nil)
78
+ # TODO: rewrite with signal
75
79
  exclusive do
76
- send_command :break_chain, 'all'
77
- send_command :stop, 'all'
78
- send_command :freeze, 'all'
80
+ apply(%w[all], command: :break_chain)
81
+ apply(%w[all], command: :stop, freeze: true)
79
82
  end
80
83
 
81
84
  # wait until all processes goes to unmonitored
@@ -33,7 +33,7 @@ module Eye::Controller::Load
33
33
  private
34
34
 
35
35
  # regexp for clean backtrace to show for user
36
- BT_REGX = %r[/lib/eye/|lib/celluloid|internal:prelude|logger.rb:|active_support/core_ext|shellwords.rb|kernel/bootstrap].freeze
36
+ BT_REGX = %r[/lib/eye/|lib/celluloid|internal:prelude|logger.rb:|active_support/core_ext|shellwords.rb|kernel/bootstrap]
37
37
 
38
38
  def catch_load_error(filename = nil, &_block)
39
39
  { error: false, config: yield }
@@ -114,17 +114,33 @@ private
114
114
  @applications.sort_by!(&:name)
115
115
  end
116
116
 
117
+ class AppDiff
118
+
119
+ attr_reader :old_groups, :old_processes, :added_groups, :added_processes
120
+
121
+ def initialize
122
+ @old_groups = {}
123
+ @old_processes = {}
124
+ @added_groups = []
125
+ @added_processes = []
126
+ end
127
+
128
+ def remove_added_processes(processes)
129
+ @added_processes -= processes
130
+ end
131
+
132
+ end
133
+
117
134
  def update_or_create_application(app_name, app_config)
118
- @old_groups = {}
119
- @old_processes = {}
135
+ diff = AppDiff.new
120
136
 
121
137
  app = @applications.detect { |c| c.name == app_name }
122
138
 
123
139
  if app
124
140
  app.groups.each do |group|
125
- @old_groups[group.name] = group
141
+ diff.old_groups[group.name] = group
126
142
  group.processes.each do |proc|
127
- @old_processes[group.name + ':' + proc.name] = proc
143
+ diff.old_processes[group.name + ':' + proc.name] = proc
128
144
  end
129
145
  end
130
146
 
@@ -136,86 +152,81 @@ private
136
152
  end
137
153
 
138
154
  app = Eye::Application.new(app_name, app_config)
139
- @applications << app
140
- @added_groups = []
141
- @added_processes = []
142
155
 
143
156
  new_groups = app_config.delete(:groups) || {}
144
157
  new_groups.each do |group_name, group_cfg|
145
- group = update_or_create_group(group_name, group_cfg.clone)
158
+ group = update_or_create_group(group_name, group_cfg.clone, diff)
146
159
  app.add_group(group)
147
160
  group.resort_processes
148
161
  end
149
162
 
150
- # now, need to clear @old_groups, and @old_processes
151
- @old_groups.each do |_, group|
163
+ diff.old_groups.each do |_, group|
152
164
  group.clear
153
- group.send_command(:delete)
165
+ group.send_call(command: :delete, reason: 'load by user')
166
+ end
167
+
168
+ diff.old_processes.each do |_, process|
169
+ process.send_call(command: :delete, reason: 'load by user') if process.alive?
154
170
  end
155
- @old_processes.each { |_, process| process.send_command(:delete) if process.alive? }
156
171
 
157
172
  # schedule monitoring for new groups, processes
158
173
  added_fully_groups = []
159
- @added_groups.each do |group|
160
- if group.processes.size > 0 && (group.processes.pure - @added_processes).size == 0
174
+ diff.added_groups.each do |group|
175
+ if !group.processes.empty? && (group.processes.pure - diff.added_processes).empty?
161
176
  added_fully_groups << group
162
- @added_processes -= group.processes.pure
177
+ diff.remove_added_processes(group.processes.pure)
163
178
  end
164
179
  end
165
180
 
166
- added_fully_groups.each { |group| group.send_command :monitor }
167
- @added_processes.each { |process| process.send_command :monitor }
168
-
169
- # remove links to prevent memory leaks
170
- @old_groups = nil
171
- @old_processes = nil
172
- @added_groups = nil
173
- @added_processes = nil
181
+ added_fully_groups.each { |group| group.send_call command: :monitor, reason: 'load by user' }
182
+ diff.added_processes.each { |process| process.send_call command: :monitor, reason: 'load by user' }
174
183
 
175
184
  app.resort_groups
176
185
 
186
+ @applications << app
187
+
177
188
  app
178
189
  end
179
190
 
180
- def update_or_create_group(group_name, group_config)
181
- group = if @old_groups[group_name]
191
+ def update_or_create_group(group_name, group_config, diff)
192
+ group = if diff.old_groups[group_name]
182
193
  debug { "updating group: #{group_name}" }
183
- group = @old_groups.delete(group_name)
184
- group.schedule :update_config, group_config, Eye::Reason::User.new(:'load config')
194
+ group = diff.old_groups.delete(group_name)
195
+ group.send_call command: :update_config, args: [group_config], reason: 'load by user'
185
196
  group.clear
186
197
  group
187
198
  else
188
199
  debug { "creating group: #{group_name}" }
189
200
  gr = Eye::Group.new(group_name, group_config)
190
- @added_groups << gr
201
+ diff.added_groups << gr
191
202
  gr
192
203
  end
193
204
 
194
205
  processes = group_config.delete(:processes) || {}
195
206
  processes.each do |process_name, process_cfg|
196
- process = update_or_create_process(process_name, process_cfg.clone)
207
+ process = update_or_create_process(process_name, process_cfg.clone, diff)
197
208
  group.add_process(process)
198
209
  end
199
210
 
200
211
  group
201
212
  end
202
213
 
203
- def update_or_create_process(process_name, process_cfg)
214
+ def update_or_create_process(process_name, process_cfg, diff)
204
215
  postfix = ':' + process_name
205
216
  name = process_cfg[:group] + postfix
206
- key = @old_processes[name] ? name : @old_processes.keys.detect { |n| n.end_with?(postfix) }
217
+ key = diff.old_processes[name] ? name : diff.old_processes.keys.detect { |n| n.end_with?(postfix) }
207
218
 
208
- if @old_processes[key]
219
+ if diff.old_processes[key]
209
220
  debug { "updating process: #{name}" }
210
- process = @old_processes.delete(key)
211
- process.schedule :update_config, process_cfg, Eye::Reason::User.new(:'load config')
212
- process
221
+ process = diff.old_processes.delete(key)
222
+ process.send_call command: :update_config, args: [process_cfg], reason: 'load by user'
213
223
  else
214
224
  debug { "creating process: #{name}" }
215
225
  process = Eye::Process.new(process_cfg)
216
- @added_processes << process
217
- process
226
+ diff.added_processes << process
218
227
  end
228
+
229
+ process
219
230
  end
220
231
 
221
232
  end
@@ -9,7 +9,7 @@ module Eye::Controller::Status
9
9
  about: Eye::ABOUT,
10
10
  resources: Eye::SystemResources.resources($$),
11
11
  ruby: RUBY_DESCRIPTION,
12
- gems: %w[Celluloid Celluloid::IO StateMachine NIO Timers Sigar].map { |c| gem_version(c) },
12
+ gems: %w[Celluloid Celluloid::IO StateMachines NIO Timers Sigar].map { |c| gem_version(c) },
13
13
  logger: Eye::Logger.args.present? ? [Eye::Logger.dev.to_s, *Eye::Logger.args] : Eye::Logger.dev.to_s,
14
14
  home: Eye::Local.home,
15
15
  dir: Eye::Local.dir,
@@ -35,7 +35,7 @@ module Eye::Controller::Status
35
35
  def history_data(*args)
36
36
  res = {}
37
37
  history_objects(*args).each do |process|
38
- res[process.full_name] = process.schedule_history.reject { |c| c[:state] == :check_crash }
38
+ res[process.full_name] = process.scheduler_history.reject { |c| c[:state] == :check_crash }
39
39
  end
40
40
  res
41
41
  end
@@ -15,7 +15,7 @@ class Eye::Dsl
15
15
  autoload :ConfigOpts, 'eye/dsl/config_opts'
16
16
  autoload :Validation, 'eye/dsl/validation'
17
17
 
18
- class Error < Exception; end
18
+ class Error < RuntimeError; end
19
19
 
20
20
  class << self
21
21
 
@@ -34,7 +34,7 @@ class Eye::Dsl::ApplicationOpts < Eye::Dsl::Opts
34
34
  res
35
35
  end
36
36
 
37
- alias_method :xgroup, :nop
38
- alias_method :xprocess, :nop
37
+ alias xgroup nop
38
+ alias xprocess nop
39
39
 
40
40
  end
@@ -8,6 +8,6 @@ class Eye::Dsl::ChildProcessOpts < Eye::Dsl::Opts
8
8
  def triggers(*_args)
9
9
  raise Eye::Dsl::Error, 'triggers not allowed in monitor_children'
10
10
  end
11
- alias_method :trigger, :triggers
11
+ alias trigger triggers
12
12
 
13
13
  end
@@ -10,7 +10,7 @@ class Eye::Dsl::ConfigOpts < Eye::Dsl::PureOpts
10
10
  @config[:logger] = args
11
11
  end
12
12
  end
13
- alias_method :logger=, :logger
13
+ alias logger= logger
14
14
 
15
15
  def syslog(name = 'eye', *args)
16
16
  require 'syslog/logger'
@@ -25,8 +25,8 @@ class Eye::Dsl::GroupOpts < Eye::Dsl::Opts
25
25
  opts
26
26
  end
27
27
 
28
- alias_method :xprocess, :nop
29
- alias_method :application, :parent
30
- alias_method :app, :application
28
+ alias xprocess nop
29
+ alias application parent
30
+ alias app application
31
31
 
32
32
  end
@@ -20,8 +20,8 @@ module Eye::Dsl::Main
20
20
  Eye::Dsl.debug { "<= app: #{name}" }
21
21
  end
22
22
 
23
- alias_method :project, :application
24
- alias_method :app, :application
23
+ alias project application
24
+ alias app application
25
25
 
26
26
  def load(glob = '')
27
27
  return if glob.blank?
@@ -54,7 +54,7 @@ module Eye::Dsl::Main
54
54
  Eye::Dsl.debug { '<= config' }
55
55
  end
56
56
 
57
- alias_method :settings, :config
57
+ alias settings config
58
58
 
59
59
  def shared
60
60
  require 'ostruct'
@@ -1,16 +1,16 @@
1
1
  class Eye::Dsl::Opts < Eye::Dsl::PureOpts
2
2
 
3
3
  STR_OPTIONS = [:pid_file, :working_dir, :stdout, :stderr, :stdall, :stdin, :start_command,
4
- :stop_command, :restart_command, :uid, :gid]
4
+ :stop_command, :restart_command, :uid, :gid].freeze
5
5
  create_options_methods(STR_OPTIONS, String)
6
6
 
7
7
  BOOL_OPTIONS = [:daemonize, :keep_alive, :auto_start, :stop_on_delete, :clear_pid, :preserve_fds, :use_leaf_child,
8
- :clear_env, :check_identity]
8
+ :clear_env, :check_identity].freeze
9
9
  create_options_methods(BOOL_OPTIONS, [TrueClass, FalseClass])
10
10
 
11
11
  INTERVAL_OPTIONS = [:check_alive_period, :start_timeout, :restart_timeout, :stop_timeout, :start_grace,
12
12
  :restart_grace, :stop_grace, :children_update_period, :restore_in,
13
- :auto_update_pidfile_grace, :revert_fuckup_pidfile_grace, :check_identity_period, :check_identity_grace]
13
+ :auto_update_pidfile_grace, :revert_fuckup_pidfile_grace, :check_identity_period, :check_identity_grace].freeze
14
14
  create_options_methods(INTERVAL_OPTIONS, [Fixnum, Float])
15
15
 
16
16
  create_options_methods([:environment], Hash)
@@ -62,10 +62,10 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
62
62
  @config[:triggers].try :delete, nac[:name]
63
63
  end
64
64
 
65
- alias_method :check, :checks
66
- alias_method :nocheck, :nochecks
67
- alias_method :trigger, :triggers
68
- alias_method :notrigger, :notriggers
65
+ alias check checks
66
+ alias nocheck nochecks
67
+ alias trigger triggers
68
+ alias notrigger notriggers
69
69
 
70
70
  def command(cmd, arg)
71
71
  @config[:user_commands] ||= {}
@@ -119,8 +119,8 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
119
119
  @config[:environment].merge!(value)
120
120
  end
121
121
 
122
- alias_method :dir, :working_dir
123
- alias_method :env, :environment
122
+ alias dir working_dir
123
+ alias env environment
124
124
 
125
125
  def set_stdall(value)
126
126
  super
@@ -182,20 +182,16 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
182
182
  def load_env(filename = '~/.env', raise_when_no_file = true)
183
183
  fnames = [File.expand_path(filename, @config[:working_dir]),
184
184
  File.expand_path(filename)].uniq
185
- filenames = fnames.select { |f| File.exist?(f) }
186
-
187
- if filenames.size < 1
188
- if raise_when_no_file
189
- raise Eye::Dsl::Error, "load_env not found in #{fnames}"
190
- else
191
- warn "load_env not found file: '#{filenames.first}'"
192
- return
193
- end
185
+ file = fnames.detect { |f| File.exist?(f) }
186
+
187
+ unless file
188
+ raise Eye::Dsl::Error, "load_env not found in #{fnames}" if raise_when_no_file
189
+ warn "load_env not found file: '#{filename}'"
190
+ return
194
191
  end
195
- raise Eye::Dsl::Error, "load_env conflict filenames: #{filenames}" if filenames.size > 1
196
192
 
197
- info "load_env from '#{filenames.first}'"
198
- Eye::Utils.load_env(filenames.first).each { |k, v| env k => v }
193
+ info "load_env from '#{file}'"
194
+ Eye::Utils.load_env(file).each { |k, v| env k => v }
199
195
  end
200
196
 
201
197
  def skip_group_action(act, val = true)