eye 0.8.1 → 0.9.pre

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 (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)