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
@@ -7,13 +7,13 @@ class Eye::Dsl::ProcessOpts < Eye::Dsl::Opts
7
7
  Eye::Utils.deep_merge!(@config[:monitor_children], opts.config)
8
8
  end
9
9
 
10
- alias_method :xmonitor_children, :nop
10
+ alias xmonitor_children nop
11
11
 
12
12
  def application
13
13
  parent.try(:parent)
14
14
  end
15
- alias_method :app, :application
16
- alias_method :group, :parent
15
+ alias app application
16
+ alias group parent
17
17
 
18
18
  def depend_on(names, opts = {})
19
19
  names = Array(names).map(&:to_s)
@@ -4,7 +4,7 @@ module Eye::Dsl::Validation
4
4
  base.extend(ClassMethods)
5
5
  end
6
6
 
7
- class Error < Exception; end
7
+ class Error < RuntimeError; end
8
8
 
9
9
  module ClassMethods
10
10
 
@@ -43,7 +43,7 @@ module Eye::Dsl::Validation
43
43
 
44
44
  return if param == :do
45
45
 
46
- define_method "#{param}" do
46
+ define_method param do
47
47
  value = @options[param]
48
48
  value.nil? ? self.class.defaults[param] : value
49
49
  end
@@ -4,10 +4,14 @@ class Eye::Group
4
4
 
5
5
  include Celluloid
6
6
 
7
- autoload :Chain, 'eye/group/chain'
7
+ autoload :Call, 'eye/group/call'
8
+ autoload :Chain, 'eye/group/chain'
9
+ autoload :Data, 'eye/group/data'
8
10
 
9
11
  include Eye::Process::Scheduler
12
+ include Eye::Group::Call
10
13
  include Eye::Group::Chain
14
+ include Eye::Group::Data
11
15
 
12
16
  attr_reader :processes, :name, :hidden, :config
13
17
 
@@ -31,11 +35,6 @@ class Eye::Group
31
35
  @full_name ||= "#{app_name}:#{@name}"
32
36
  end
33
37
 
34
- def update_config(cfg)
35
- @config = cfg
36
- @full_name = nil
37
- end
38
-
39
38
  def add_process(process)
40
39
  @processes << process
41
40
  end
@@ -45,99 +44,6 @@ class Eye::Group
45
44
  @processes = @processes.sort_by(&:name)
46
45
  end
47
46
 
48
- def status_data(opts = {})
49
- plist = @processes.map { |p| p.status_data(opts) }
50
-
51
- h = { name: name, type: :group, subtree: plist }
52
-
53
- h[:debug] = debug_data if opts[:debug]
54
-
55
- # show current chain
56
- if current_scheduled_command
57
- h.update(current_command: current_scheduled_command)
58
-
59
- if (chain_commands = scheduler_actions_list) && chain_commands.present?
60
- h.update(chain_commands: chain_commands)
61
- end
62
-
63
- if @chain_processes_current && @chain_processes_count
64
- h.update(chain_progress: [@chain_processes_current, @chain_processes_count])
65
- end
66
- end
67
-
68
- h
69
- end
70
-
71
- def status_data_short
72
- h = {}
73
- @processes.each do |p|
74
- state = p.state
75
- h[state] ||= 0
76
- h[state] += 1
77
- end
78
- { name: (@name == '__default__' ? 'default' : @name), type: :group, states: h }
79
- end
80
-
81
- def debug_data
82
- { queue: scheduler_actions_list, chain: chain_status }
83
- end
84
-
85
- def send_command(command, *args)
86
- info "send_command: #{command}"
87
-
88
- case command
89
- when :delete
90
- delete(*args)
91
- when :break_chain
92
- break_chain(*args)
93
- else
94
- schedule command, *args, Eye::Reason::User.new(command)
95
- end
96
- end
97
-
98
- def start
99
- chain_command :start
100
- end
101
-
102
- def stop
103
- async_schedule :stop
104
- end
105
-
106
- def restart
107
- chain_command :restart
108
- end
109
-
110
- def delete
111
- async_schedule :delete
112
- terminate
113
- end
114
-
115
- def monitor
116
- chain_command :monitor
117
- end
118
-
119
- def unmonitor
120
- async_schedule :unmonitor
121
- end
122
-
123
- def signal(sig)
124
- async_schedule :signal, sig
125
- end
126
-
127
- def user_command(cmd)
128
- async_schedule :user_command, cmd
129
- end
130
-
131
- def break_chain
132
- info 'break chain'
133
- scheduler_clear_pending_list
134
- @chain_breaker = true
135
- end
136
-
137
- def freeze
138
- async_schedule :freeze
139
- end
140
-
141
47
  def clear
142
48
  @processes = Eye::Utils::AliveArray.new
143
49
  end
@@ -150,22 +56,10 @@ class Eye::Group
150
56
  def <=>(other)
151
57
  if hidden
152
58
  1
59
+ elsif other.hidden
60
+ -1
153
61
  else
154
- if other.hidden
155
- -1
156
- else
157
- name <=> other.name
158
- end
159
- end
160
- end
161
-
162
- private
163
-
164
- def async_schedule(command, *args)
165
- info "send to all processes #{command} #{args.present? ? args * ',' : nil}"
166
-
167
- @processes.each do |process|
168
- process.send_command(command, *args) unless process.skip_group_action?(command)
62
+ name <=> other.name
169
63
  end
170
64
  end
171
65
 
@@ -0,0 +1,73 @@
1
+ module Eye::Group::Call
2
+
3
+ # :update_config, :start, :stop, :restart, :unmonitor, :monitor, :break_chain, :delete, :signal, :user_command
4
+ def send_call(call)
5
+ info "call: #{call[:method]}"
6
+
7
+ case call[:command]
8
+ when :delete
9
+ delete
10
+ when :break_chain
11
+ break_chain
12
+ else
13
+ user_schedule(call)
14
+ end
15
+ end
16
+
17
+ def update_config(cfg)
18
+ @config = cfg
19
+ @full_name = nil
20
+ end
21
+
22
+ def start
23
+ chained_call command: :start
24
+ end
25
+
26
+ def stop
27
+ fast_call command: :stop
28
+ end
29
+
30
+ def restart
31
+ chained_call command: :restart
32
+ end
33
+
34
+ def delete
35
+ fast_call command: :delete
36
+ terminate
37
+ end
38
+
39
+ def monitor
40
+ chained_call command: :monitor
41
+ end
42
+
43
+ def unmonitor
44
+ fast_call command: :unmonitor
45
+ end
46
+
47
+ def signal(sig)
48
+ fast_call command: :signal, args: [sig]
49
+ end
50
+
51
+ def user_command(cmd)
52
+ fast_call command: :user_command, args: [cmd]
53
+ end
54
+
55
+ def break_chain
56
+ info 'break chain'
57
+ scheduler_clear_pending_list
58
+ @chain_breaker = true
59
+ end
60
+
61
+ private
62
+
63
+ def fast_call(call)
64
+ command = call[:command]
65
+ args = call[:args]
66
+ info "send to all processes #{command} #{args.present? ? args * ',' : nil}"
67
+
68
+ @processes.each do |process|
69
+ process.send_call(call) unless process.skip_group_action?(command)
70
+ end
71
+ end
72
+
73
+ end
@@ -2,7 +2,14 @@ module Eye::Group::Chain
2
2
 
3
3
  private
4
4
 
5
- def chain_schedule(type, grace, command, *args)
5
+ def chained_call(call)
6
+ type, grace = chain_options(call[:command])
7
+ chain_schedule(type, grace, call)
8
+ end
9
+
10
+ def chain_schedule(type, grace, call)
11
+ command = call[:command]
12
+ args = call[:args]
6
13
  info "starting #{type} with #{grace}s chain #{command} #{args}"
7
14
 
8
15
  @chain_processes_count = @processes.size
@@ -17,7 +24,7 @@ private
17
24
  next
18
25
  end
19
26
 
20
- chain_schedule_process(process, type, command, *args)
27
+ chain_schedule_process(process, type, call)
21
28
 
22
29
  @chain_processes_current = @chain_processes_current.to_i + 1
23
30
 
@@ -37,18 +44,18 @@ private
37
44
  @chain_processes_current = nil
38
45
  end
39
46
 
40
- def chain_schedule_process(process, type, command, *args)
41
- debug { "chain_schedule_process #{process.name} #{type} #{command}" }
47
+ def chain_schedule_process(process, type, call)
48
+ debug { "chain_schedule_process #{process.name} #{type} #{call[:command]}" }
42
49
 
43
50
  if type == :sync
44
51
  # sync command, with waiting
45
- # this is very hackety, because call method of the process without its scheduler
46
- # need to provide some scheduler future
47
- process.last_scheduled_reason = last_scheduled_reason
48
- process.send(command, *args)
52
+ Eye::Utils.wait_signal(call[:signal_timeout]) do |signal|
53
+ process.send_call(call.merge(signal: signal))
54
+ end
55
+
49
56
  else
50
57
  # async command
51
- process.send_command(command, *args)
58
+ process.send_call(call)
52
59
  end
53
60
  end
54
61
 
@@ -58,11 +65,6 @@ private
58
65
  end
59
66
  end
60
67
 
61
- def chain_command(command, *args)
62
- chain_opts = chain_options(command)
63
- chain_schedule(chain_opts[:type], chain_opts[:grace], command, *args)
64
- end
65
-
66
68
  # with such delay will chained processes by default
67
69
  DEFAULT_CHAIN = 0.2
68
70
 
@@ -74,12 +76,12 @@ private
74
76
  type = [:async, :sync].include?(type) ? type : :async
75
77
 
76
78
  grace = @config[:chain][command].try :[], :grace
77
- grace = grace ? (grace.to_f rescue DEFAULT_CHAIN) : DEFAULT_CHAIN
79
+ grace = (grace || DEFAULT_CHAIN).to_f rescue DEFAULT_CHAIN
78
80
 
79
- { type: type, grace: grace }
81
+ [type, grace]
80
82
  else
81
83
  # default chain case
82
- { type: :async, grace: DEFAULT_CHAIN }
84
+ [:async, DEFAULT_CHAIN]
83
85
  end
84
86
  end
85
87
 
@@ -0,0 +1,40 @@
1
+ module Eye::Group::Data
2
+
3
+ def status_data(opts = {})
4
+ plist = @processes.map { |p| p.status_data(opts) }
5
+
6
+ h = { name: name, type: :group, subtree: plist }
7
+
8
+ h[:debug] = debug_data if opts[:debug]
9
+
10
+ # show current chain
11
+ if scheduled_call = @scheduled_call
12
+ h[:current_command] = scheduled_call[:command]
13
+
14
+ if (chain_commands = scheduler_commands_list) && chain_commands.present?
15
+ h[:chain_commands] = chain_commands
16
+ end
17
+
18
+ if @chain_processes_current && @chain_processes_count
19
+ h[:chain_progress] = [@chain_processes_current, @chain_processes_count]
20
+ end
21
+ end
22
+
23
+ h
24
+ end
25
+
26
+ def status_data_short
27
+ h = {}
28
+ @processes.each do |p|
29
+ state = p.state
30
+ h[state] ||= 0
31
+ h[state] += 1
32
+ end
33
+ { name: (@name == '__default__' ? 'default' : @name), type: :group, states: h }
34
+ end
35
+
36
+ def debug_data
37
+ { queue: scheduler_commands_list, chain: chain_status }
38
+ end
39
+
40
+ end
@@ -6,5 +6,5 @@ gem 'celluloid-io', '~> 0.17.0'
6
6
  gem 'nio4r'
7
7
  gem 'timers'
8
8
 
9
- gem 'state_machine'
9
+ gem 'state_machines'
10
10
  gem 'sigar', '~> 0.7.3'
@@ -6,7 +6,7 @@ class Eye::Logger
6
6
 
7
7
  class InnerLogger < Logger
8
8
 
9
- FORMAT = '%d.%m.%Y %H:%M:%S'
9
+ FORMAT = '%d.%m.%Y %H:%M:%S'.freeze
10
10
 
11
11
  def initialize(*args)
12
12
  super
@@ -39,7 +39,7 @@ class Eye::Logger
39
39
  end
40
40
 
41
41
  def log_ex(ex)
42
- error "#{ex.message} #{ex.backtrace}"
42
+ error "Exception: #{ex.message} #{ex.backtrace}"
43
43
  # notify here?
44
44
  end
45
45
 
@@ -73,8 +73,8 @@ class Eye::Logger
73
73
  if dev.nil?
74
74
  @inner_logger = InnerLogger.new(nil)
75
75
  elsif dev.is_a?(String)
76
- @dev_fd = STDOUT if @dev.to_s.downcase == 'stdout'
77
- @dev_fd = STDERR if @dev.to_s.downcase == 'stderr'
76
+ @dev_fd = STDOUT if @dev.to_s.casecmp('stdout') == 0
77
+ @dev_fd = STDERR if @dev.to_s.casecmp('stderr') == 0
78
78
  @inner_logger = InnerLogger.new(@dev_fd, *args)
79
79
  else
80
80
  @inner_logger = dev
@@ -35,6 +35,8 @@ class Eye::Process
35
35
  @states_history = Eye::Process::StatesHistory.new(100)
36
36
  @states_history << :unmonitored
37
37
 
38
+ @state_call = {}
39
+
38
40
  debug { "creating with config: #{@config.inspect}" }
39
41
 
40
42
  add_triggers
@@ -7,7 +7,7 @@ module Eye::Process::Commands
7
7
 
8
8
  unless self[:start_command]
9
9
  warn 'no :start_command found, unmonitoring'
10
- switch :unmonitoring, Eye::Reason.new(:no_start_command)
10
+ switch :unmonitoring, reason: 'no_start_command'
11
11
  return :no_start_command
12
12
  end
13
13
 
@@ -30,7 +30,7 @@ module Eye::Process::Commands
30
30
 
31
31
  result
32
32
 
33
- rescue StateMachine::InvalidTransition, Eye::Process::StateError => e
33
+ rescue StateMachines::InvalidTransition, Eye::Process::StateError => e
34
34
  warn "wrong switch '#{e.message}'"
35
35
 
36
36
  :state_error
@@ -48,7 +48,7 @@ module Eye::Process::Commands
48
48
  if process_really_running?
49
49
  warn "process <#{self.pid}> was not stopped; try checking your command/signals or tuning the stop_timeout/stop_grace values"
50
50
 
51
- switch :unmonitoring, Eye::Reason.new(:'not stopped (soft command)')
51
+ switch :unmonitoring, reason: 'not stopped (soft command)'
52
52
  nil
53
53
 
54
54
  else
@@ -59,7 +59,7 @@ module Eye::Process::Commands
59
59
  true
60
60
  end
61
61
 
62
- rescue StateMachine::InvalidTransition, Eye::Process::StateError => e
62
+ rescue StateMachines::InvalidTransition, Eye::Process::StateError => e
63
63
  warn "wrong switch '#{e.message}'"
64
64
  nil
65
65
  end
@@ -83,7 +83,7 @@ module Eye::Process::Commands
83
83
 
84
84
  true
85
85
 
86
- rescue StateMachine::InvalidTransition, Eye::Process::StateError => e
86
+ rescue StateMachines::InvalidTransition, Eye::Process::StateError => e
87
87
  warn "wrong switch '#{e.message}'"
88
88
  nil
89
89
  end
@@ -121,7 +121,7 @@ private
121
121
  delay = stop_signals.shift
122
122
  signal = stop_signals.shift
123
123
 
124
- if wait_for_condition(delay.to_f, 0.3) { !process_really_running? }
124
+ if wait_for_condition(delay.to_f, 0.1) { !process_really_running? }
125
125
  info 'has terminated'
126
126
  break
127
127
  end
@@ -129,19 +129,11 @@ private
129
129
  send_signal(signal) if signal
130
130
  end
131
131
 
132
- sleep_grace(:stop_grace)
133
-
134
- else # default command
135
- debug { "executing: `kill -TERM #{self.pid}` with stop_grace: #{self[:stop_grace].to_f}s" }
136
- send_signal(:TERM)
137
- sleep_grace(:stop_grace)
138
-
139
- # if process not die here, by default we force kill it
140
- if process_really_running?
141
- warn "process <#{self.pid}> did not die after TERM, sending KILL"
142
- send_signal(:KILL)
143
- sleep 0.1 # little grace
144
- end
132
+ # little grace
133
+ sleep 0.1
134
+ else
135
+ # TODO, notify here?
136
+ error 'stop_command or stop_signals should be'
145
137
  end
146
138
  end
147
139