eye 0.8.1 → 0.9.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|