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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +21 -2
- data/.travis.yml +2 -1
- data/Gemfile +3 -0
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/bin/loader_eye +1 -1
- data/examples/delayed_job.eye +2 -2
- data/examples/processes/sample.rb +1 -1
- data/examples/puma.eye +1 -1
- data/examples/rbenv.eye +1 -1
- data/examples/sidekiq.eye +1 -1
- data/examples/test.eye +1 -1
- data/examples/thin-farm.eye +1 -1
- data/examples/unicorn.eye +1 -1
- data/eye.gemspec +2 -2
- data/lib/eye.rb +2 -3
- data/lib/eye/application.rb +3 -6
- data/lib/eye/checker.rb +4 -3
- data/lib/eye/checker/children_count.rb +3 -3
- data/lib/eye/checker/socket.rb +7 -12
- data/lib/eye/child_process.rb +5 -7
- data/lib/eye/cli.rb +6 -4
- data/lib/eye/cli/commands.rb +1 -1
- data/lib/eye/cli/render.rb +6 -5
- data/lib/eye/client.rb +9 -4
- data/lib/eye/controller.rb +2 -2
- data/lib/eye/controller/{send_command.rb → apply.rb} +25 -32
- data/lib/eye/controller/commands.rb +13 -10
- data/lib/eye/controller/load.rb +49 -38
- data/lib/eye/controller/status.rb +2 -2
- data/lib/eye/dsl.rb +1 -1
- data/lib/eye/dsl/application_opts.rb +2 -2
- data/lib/eye/dsl/child_process_opts.rb +1 -1
- data/lib/eye/dsl/config_opts.rb +1 -1
- data/lib/eye/dsl/group_opts.rb +3 -3
- data/lib/eye/dsl/main.rb +3 -3
- data/lib/eye/dsl/opts.rb +17 -21
- data/lib/eye/dsl/process_opts.rb +3 -3
- data/lib/eye/dsl/validation.rb +2 -2
- data/lib/eye/group.rb +8 -114
- data/lib/eye/group/call.rb +73 -0
- data/lib/eye/group/chain.rb +19 -17
- data/lib/eye/group/data.rb +40 -0
- data/lib/eye/loader.rb +1 -1
- data/lib/eye/logger.rb +4 -4
- data/lib/eye/process.rb +2 -0
- data/lib/eye/process/commands.rb +11 -19
- data/lib/eye/process/config.rb +2 -1
- data/lib/eye/process/controller.rb +5 -12
- data/lib/eye/process/data.rb +11 -3
- data/lib/eye/process/monitor.rb +5 -5
- data/lib/eye/process/notify.rb +1 -1
- data/lib/eye/process/scheduler.rb +118 -63
- data/lib/eye/process/states.rb +10 -9
- data/lib/eye/process/states_history.rb +1 -1
- data/lib/eye/process/system.rb +1 -1
- data/lib/eye/process/trigger.rb +5 -4
- data/lib/eye/process/validate.rb +1 -1
- data/lib/eye/server.rb +22 -9
- data/lib/eye/trigger.rb +4 -7
- data/lib/eye/trigger/check_dependency.rb +1 -1
- data/lib/eye/trigger/flapping.rb +8 -10
- data/lib/eye/trigger/starting_guard.rb +7 -4
- data/lib/eye/trigger/stop_children.rb +1 -1
- data/lib/eye/trigger/wait_dependency.rb +2 -2
- data/lib/eye/utils.rb +19 -9
- metadata +10 -10
- data/lib/eye/reason.rb +0 -26
- data/lib/eye/utils/celluloid_chain.rb +0 -73
data/lib/eye/controller.rb
CHANGED
@@ -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 :
|
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::
|
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::
|
1
|
+
module Eye::Controller::Apply
|
2
2
|
|
3
|
-
def
|
4
|
-
matched_objects(*
|
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
|
-
|
20
|
-
matched_objects(*args) do |obj|
|
21
|
-
obj.send_command :signal, signal || 0
|
22
|
-
end
|
23
|
-
end
|
20
|
+
private
|
24
21
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
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
|
-
|
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
|
-
|
79
|
-
|
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
|
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
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
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
|
-
|
21
|
+
apply(args, command: cmd, signal: opts[:signal])
|
19
22
|
when :delete
|
20
|
-
exclusive {
|
21
|
-
when :signal
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
77
|
-
|
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
|
data/lib/eye/controller/load.rb
CHANGED
@@ -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]
|
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
|
-
|
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
|
-
|
141
|
+
diff.old_groups[group.name] = group
|
126
142
|
group.processes.each do |proc|
|
127
|
-
|
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
|
-
|
151
|
-
@old_groups.each do |_, group|
|
163
|
+
diff.old_groups.each do |_, group|
|
152
164
|
group.clear
|
153
|
-
group.
|
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
|
-
|
160
|
-
if group.processes.
|
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
|
-
|
177
|
+
diff.remove_added_processes(group.processes.pure)
|
163
178
|
end
|
164
179
|
end
|
165
180
|
|
166
|
-
added_fully_groups.each { |group| group.
|
167
|
-
|
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
|
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 =
|
184
|
-
group.
|
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
|
-
|
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 =
|
217
|
+
key = diff.old_processes[name] ? name : diff.old_processes.keys.detect { |n| n.end_with?(postfix) }
|
207
218
|
|
208
|
-
if
|
219
|
+
if diff.old_processes[key]
|
209
220
|
debug { "updating process: #{name}" }
|
210
|
-
process =
|
211
|
-
process.
|
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
|
-
|
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
|
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.
|
38
|
+
res[process.full_name] = process.scheduler_history.reject { |c| c[:state] == :check_crash }
|
39
39
|
end
|
40
40
|
res
|
41
41
|
end
|
data/lib/eye/dsl.rb
CHANGED
data/lib/eye/dsl/config_opts.rb
CHANGED
data/lib/eye/dsl/group_opts.rb
CHANGED
data/lib/eye/dsl/main.rb
CHANGED
@@ -20,8 +20,8 @@ module Eye::Dsl::Main
|
|
20
20
|
Eye::Dsl.debug { "<= app: #{name}" }
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
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
|
-
|
57
|
+
alias settings config
|
58
58
|
|
59
59
|
def shared
|
60
60
|
require 'ostruct'
|
data/lib/eye/dsl/opts.rb
CHANGED
@@ -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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
123
|
-
|
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
|
-
|
186
|
-
|
187
|
-
|
188
|
-
if raise_when_no_file
|
189
|
-
|
190
|
-
|
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 '#{
|
198
|
-
Eye::Utils.load_env(
|
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)
|