reel-eye 0.3.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -1
  4. data/.travis.yml +3 -1
  5. data/CHANGES.md +11 -2
  6. data/Gemfile +1 -0
  7. data/README.md +18 -14
  8. data/Rakefile +10 -3
  9. data/bin/eye +41 -27
  10. data/examples/process_thin.rb +1 -1
  11. data/examples/processes/em.rb +2 -2
  12. data/examples/processes/forking.rb +2 -2
  13. data/examples/processes/sample.rb +5 -5
  14. data/examples/rbenv.eye +1 -1
  15. data/examples/sidekiq.eye +2 -2
  16. data/examples/test.eye +10 -6
  17. data/examples/thin-farm.eye +1 -1
  18. data/examples/unicorn.eye +1 -1
  19. data/eye.gemspec +13 -7
  20. data/lib/eye.rb +6 -6
  21. data/lib/eye/application.rb +9 -6
  22. data/lib/eye/checker.rb +51 -21
  23. data/lib/eye/checker/file_size.rb +1 -1
  24. data/lib/eye/checker/http.rb +3 -3
  25. data/lib/eye/checker/memory.rb +1 -1
  26. data/lib/eye/checker/socket.rb +6 -6
  27. data/lib/eye/child_process.rb +7 -11
  28. data/lib/eye/client.rb +6 -6
  29. data/lib/eye/config.rb +2 -2
  30. data/lib/eye/controller.rb +13 -8
  31. data/lib/eye/controller/commands.rb +9 -10
  32. data/lib/eye/controller/helpers.rb +1 -0
  33. data/lib/eye/controller/load.rb +11 -7
  34. data/lib/eye/controller/options.rb +1 -1
  35. data/lib/eye/controller/send_command.rb +44 -19
  36. data/lib/eye/controller/show_history.rb +8 -7
  37. data/lib/eye/controller/status.rb +39 -26
  38. data/lib/eye/dsl.rb +3 -3
  39. data/lib/eye/dsl/application_opts.rb +4 -4
  40. data/lib/eye/dsl/config_opts.rb +4 -4
  41. data/lib/eye/dsl/helpers.rb +2 -2
  42. data/lib/eye/dsl/main.rb +2 -2
  43. data/lib/eye/dsl/opts.rb +19 -14
  44. data/lib/eye/dsl/process_opts.rb +1 -1
  45. data/lib/eye/dsl/pure_opts.rb +2 -2
  46. data/lib/eye/dsl/validation.rb +7 -5
  47. data/lib/eye/group.rb +17 -11
  48. data/lib/eye/group/chain.rb +3 -3
  49. data/lib/eye/http.rb +1 -1
  50. data/lib/eye/http/router.rb +2 -2
  51. data/lib/eye/loader.rb +8 -7
  52. data/lib/eye/logger.rb +14 -5
  53. data/lib/eye/notify.rb +13 -7
  54. data/lib/eye/notify/jabber.rb +2 -2
  55. data/lib/eye/notify/mail.rb +2 -2
  56. data/lib/eye/process.rb +10 -13
  57. data/lib/eye/process/child.rb +1 -1
  58. data/lib/eye/process/commands.rb +34 -32
  59. data/lib/eye/process/config.rb +17 -12
  60. data/lib/eye/process/controller.rb +3 -6
  61. data/lib/eye/process/data.rb +16 -5
  62. data/lib/eye/process/monitor.rb +12 -5
  63. data/lib/eye/process/notify.rb +1 -1
  64. data/lib/eye/process/scheduler.rb +3 -3
  65. data/lib/eye/process/states.rb +10 -13
  66. data/lib/eye/process/states_history.rb +3 -3
  67. data/lib/eye/process/system.rb +17 -21
  68. data/lib/eye/process/trigger.rb +11 -30
  69. data/lib/eye/process/watchers.rb +9 -9
  70. data/lib/eye/server.rb +14 -6
  71. data/lib/eye/settings.rb +4 -4
  72. data/lib/eye/system.rb +10 -7
  73. data/lib/eye/system_resources.rb +4 -4
  74. data/lib/eye/trigger.rb +58 -21
  75. data/lib/eye/trigger/flapping.rb +24 -4
  76. data/lib/eye/trigger/state.rb +28 -0
  77. data/lib/eye/utils/alive_array.rb +1 -1
  78. data/lib/eye/utils/celluloid_klass.rb +5 -0
  79. data/lib/eye/utils/pmap.rb +7 -0
  80. data/lib/eye/utils/tail.rb +1 -1
  81. metadata +252 -271
  82. data/lib/eye/utils/leak_19.rb +0 -7
@@ -1,10 +1,10 @@
1
1
  class Eye::Notify::Jabber < Eye::Notify
2
-
2
+
3
3
  # Eye.config do
4
4
  # jabber :host => "some.host", :port => 12345, :user => "eye@some.host", :password => "123456"
5
5
  # contact :vasya, :jabber, "vasya@some.host"
6
6
  # end
7
-
7
+
8
8
  param :host, String, true
9
9
  param :port, [String, Fixnum], true
10
10
  param :user, String, true
@@ -14,10 +14,10 @@ class Eye::Notify::Mail < Eye::Notify
14
14
  param :user, String
15
15
  param :password, String
16
16
  param :auth, Symbol, nil, nil, [:plain, :login, :cram_md5]
17
-
17
+
18
18
  param :from_mail, String
19
19
  param :from_name, String, nil, 'eye'
20
-
20
+
21
21
  def execute
22
22
  smtp
23
23
  end
data/lib/eye/process.rb CHANGED
@@ -2,7 +2,7 @@ require 'celluloid'
2
2
 
3
3
  class Eye::Process
4
4
  include Celluloid
5
-
5
+
6
6
  autoload :Config, 'eye/process/config'
7
7
  autoload :Commands, 'eye/process/commands'
8
8
  autoload :Data, 'eye/process/data'
@@ -17,19 +17,19 @@ class Eye::Process
17
17
  autoload :Scheduler, 'eye/process/scheduler'
18
18
  autoload :Validate, 'eye/process/validate'
19
19
 
20
- attr_accessor :pid, :watchers, :config, :states_history,
21
- :childs, :triggers, :name, :state_reason
22
-
20
+ attr_accessor :pid, :watchers, :config, :states_history,
21
+ :childs, :triggers, :name, :state_reason, :flapping_times
22
+
23
23
  def initialize(config)
24
24
  raise 'pid file should be' unless config[:pid_file]
25
25
 
26
26
  @config = prepare_config(config)
27
- @logger = Eye::Logger.new(full_name)
28
27
 
29
28
  @watchers = {}
30
29
  @childs = {}
31
30
  @triggers = []
32
31
  @name = @config[:name]
32
+ @flapping_times = 0
33
33
 
34
34
  @states_history = Eye::Process::StatesHistory.new(100)
35
35
  @states_history << :unmonitored
@@ -41,22 +41,22 @@ class Eye::Process
41
41
  super() # for statemachine
42
42
  end
43
43
 
44
- # c(), self[]
44
+ # c(), self[]
45
45
  include Eye::Process::Config
46
-
46
+
47
47
  # full_name, status_data
48
48
  include Eye::Process::Data
49
-
49
+
50
50
  # commands:
51
51
  # start_process, stop_process, restart_process
52
52
  include Eye::Process::Commands
53
53
 
54
54
  # start, stop, restart, monitor, unmonit, delete
55
55
  include Eye::Process::Controller
56
-
56
+
57
57
  # add_watchers, remove_watchers:
58
58
  include Eye::Process::Watchers
59
-
59
+
60
60
  # check alive, crash methods:
61
61
  include Eye::Process::Monitor
62
62
 
@@ -72,9 +72,6 @@ class Eye::Process
72
72
  # manage notify methods
73
73
  include Eye::Process::Notify
74
74
 
75
- # logger methods
76
- include Eye::Logger::Helpers
77
-
78
75
  # scheduler
79
76
  include Eye::Process::Scheduler
80
77
 
@@ -31,7 +31,7 @@ module Eye::Process::Child
31
31
  if new_childs.present?
32
32
  new_childs.each do |child_pid|
33
33
  self.childs[child_pid] = Eye::ChildProcess.new(child_pid, self[:monitor_children], logger.prefix)
34
- end
34
+ end
35
35
  end
36
36
 
37
37
  if removed_childs.present?
@@ -7,7 +7,7 @@ module Eye::Process::Commands
7
7
 
8
8
  unless self[:start_command]
9
9
  warn 'no start command, so unmonitoring'
10
- switch :unmonitoring
10
+ switch :unmonitoring, Eye::Reason.new(:no_start_command)
11
11
  return :no_start_command
12
12
  end
13
13
 
@@ -35,7 +35,7 @@ module Eye::Process::Commands
35
35
 
36
36
  :state_error
37
37
  end
38
-
38
+
39
39
  def stop_process
40
40
  debug 'stop_process command'
41
41
 
@@ -46,19 +46,15 @@ module Eye::Process::Commands
46
46
  if process_realy_running?
47
47
  warn 'NOT STOPPED, check command/signals, or tune stop_timeout/stop_grace, seems it was really soft'
48
48
 
49
- switch :unmonitoring
49
+ switch :unmonitoring, Eye::Reason.new(:'not stopped (soft command)')
50
50
  nil
51
51
 
52
52
  else
53
53
  switch :stopped
54
54
 
55
- if control_pid?
56
- info "delete pid_file: #{self[:pid_file_ex]}"
57
- clear_pid_file
58
- end
59
-
60
- true
55
+ clear_pid_file if self[:clear_pid] # by default for all
61
56
 
57
+ true
62
58
  end
63
59
 
64
60
  rescue StateMachine::InvalidTransition => e
@@ -73,7 +69,7 @@ module Eye::Process::Commands
73
69
 
74
70
  if self[:restart_command]
75
71
  execute_restart_command
76
- sleep self[:restart_timeout].to_f
72
+ sleep_grace(:restart_grace)
77
73
  result = check_alive_with_refresh_pid_if_needed
78
74
  switch(result ? :restarted : :crashed)
79
75
  else
@@ -106,7 +102,7 @@ private
106
102
  end
107
103
  end
108
104
 
109
- sleep self[:stop_grace].to_f
105
+ sleep_grace(:stop_grace)
110
106
 
111
107
  elsif self[:stop_signals]
112
108
  info "executing stop_signals #{self[:stop_signals].inspect}"
@@ -119,7 +115,7 @@ private
119
115
  delay = stop_signals.shift
120
116
  signal = stop_signals.shift
121
117
 
122
- if wait_for_condition(delay.to_f, 0.1){ !process_realy_running? }
118
+ if wait_for_condition(delay.to_f, 0.3){ !process_realy_running? }
123
119
  info 'has terminated'
124
120
  break
125
121
  end
@@ -127,17 +123,17 @@ private
127
123
  send_signal(signal)
128
124
  end
129
125
 
130
- sleep self[:stop_grace].to_f
126
+ sleep_grace(:stop_grace)
131
127
 
132
128
  else # default command
133
- info "executing: `kill -TERM #{self.pid}` with stop_grace: #{self[:stop_grace].to_f}s"
129
+ debug "executing: `kill -TERM #{self.pid}` with stop_grace: #{self[:stop_grace].to_f}s"
134
130
  send_signal(:TERM)
135
-
136
- sleep self[:stop_grace].to_f
131
+
132
+ sleep_grace(:stop_grace)
137
133
 
138
134
  # if process not die here, by default we force kill it
139
135
  if process_realy_running?
140
- warn "process not die after TERM and stop_grace #{self[:stop_grace].to_f}s, so send KILL"
136
+ warn "process not die after TERM and stop_grace #{self[:stop_grace].to_f}s, so send KILL(#{self.pid})"
141
137
  send_signal(:KILL)
142
138
  sleep 0.1 # little grace
143
139
  end
@@ -160,7 +156,7 @@ private
160
156
 
161
157
  res
162
158
  end
163
-
159
+
164
160
  def daemonize_process
165
161
  time_before = Time.now
166
162
  res = Eye::System.daemonize(self[:start_command], config)
@@ -169,15 +165,15 @@ private
169
165
  info "daemonizing: `#{self[:start_command]}` with start_grace: #{self[:start_grace].to_f}s, env: #{self[:environment].inspect}, working_dir: #{self[:working_dir]} (pid:#{res[:pid]})"
170
166
 
171
167
  if res[:error]
172
- error "raised with #{res[:error].inspect}"
173
-
174
168
  if res[:error].message == 'Permission denied - open'
175
- error 'seems stdout/err/all files is not writable'
169
+ error "raised with #{res[:error].inspect}, seems #{[self[:stdout], self[:stderr]]} files are not writable"
170
+ else
171
+ error "raised with #{res[:error].inspect}"
176
172
  end
177
173
 
178
174
  return {:error => res[:error].inspect}
179
175
  end
180
-
176
+
181
177
  self.pid = res[:pid]
182
178
 
183
179
  unless self.pid
@@ -185,7 +181,7 @@ private
185
181
  return {:error => :empty_pid}
186
182
  end
187
183
 
188
- sleep self[:start_grace].to_f
184
+ sleep_grace(:start_grace)
189
185
 
190
186
  unless process_realy_running?
191
187
  error "process with pid(#{self.pid}) not found, may be crashed (#{check_logs_str})"
@@ -193,9 +189,9 @@ private
193
189
  end
194
190
 
195
191
  unless failsafe_save_pid
196
- return {:error => :cant_write_pid}
192
+ return {:error => :cant_write_pid}
197
193
  end
198
-
194
+
199
195
  res
200
196
  end
201
197
 
@@ -204,13 +200,13 @@ private
204
200
  time_before = Time.now
205
201
 
206
202
  res = execute(self[:start_command], config.merge(:timeout => config[:start_timeout]))
207
- start_time = Time.now - time_before
203
+ start_time = Time.now - time_before
208
204
 
209
205
  if res[:error]
210
- error "raised with #{res[:error].inspect}"
211
-
212
206
  if res[:error].message == 'Permission denied - open'
213
- error 'seems stdout/err/all files is not writable'
207
+ error "raised with #{res[:error].inspect}, seems #{[self[:stdout], self[:stderr]]} files are not writable"
208
+ else
209
+ error "raised with #{res[:error].inspect}"
214
210
  end
215
211
 
216
212
  if res[:error].class == Timeout::Error
@@ -220,7 +216,7 @@ private
220
216
  return {:error => res[:error].inspect}
221
217
  end
222
218
 
223
- sleep self[:start_grace].to_f
219
+ sleep_grace(:start_grace)
224
220
 
225
221
  unless set_pid_from_file
226
222
  error "pid_file(#{self[:pid_file_ex]}) does not appears after start_grace #{self[:start_grace].to_f}, check start_command, or tune start_grace (eye dont know what to monitor without pid)"
@@ -241,8 +237,8 @@ private
241
237
  if !self[:stdout] && !self[:stderr]
242
238
  'maybe should add stdout/err/all logs'
243
239
  else
244
- "check also it stdout/err/all logs #{[self[:stdout], self[:stderr]].inspect}"
245
- end
240
+ "check also it stdout/err/all logs #{[self[:stdout], self[:stderr]]}"
241
+ end
246
242
  end
247
243
 
248
244
  def prepare_command(command)
@@ -253,4 +249,10 @@ private
253
249
  end
254
250
  end
255
251
 
252
+ def sleep_grace(grace_name)
253
+ grace = self[grace_name].to_f
254
+ info "sleeping for :#{grace_name} #{grace}"
255
+ sleep grace
256
+ end
257
+
256
258
  end
@@ -8,14 +8,15 @@ module Eye::Process::Config
8
8
  :stop_timeout => 10.seconds,
9
9
  :restart_timeout => 10.seconds,
10
10
 
11
- :start_grace => 2.5.seconds,
12
- :stop_grace => 0.5.seconds,
13
- :restart_grace => 0.5.seconds,
11
+ :start_grace => 2.5.seconds,
12
+ :stop_grace => 0.5.seconds,
13
+ :restart_grace => 1.second,
14
14
 
15
15
  :daemonize => false,
16
16
  :auto_start => true, # auto start on monitor action
17
17
 
18
- :childs_update_period => 30.seconds
18
+ :childs_update_period => 30.seconds,
19
+ :clear_pid => true # by default clear pid on stop
19
20
  }
20
21
 
21
22
  def prepare_config(new_config)
@@ -30,25 +31,26 @@ module Eye::Process::Config
30
31
  h[:triggers] ||= {}
31
32
  h[:triggers][:flapping] = {:type => :flapping, :times => 10, :within => 10.seconds}
32
33
  end
33
-
34
+
34
35
  h[:stdout] = Eye::System.normalized_file(h[:stdout], h[:working_dir]) if h[:stdout]
35
36
  h[:stderr] = Eye::System.normalized_file(h[:stderr], h[:working_dir]) if h[:stderr]
36
37
 
37
- h
38
+ h
38
39
  end
39
40
 
40
41
  def c(name)
41
42
  @config[name]
42
43
  end
43
-
44
+
44
45
  def [](name)
45
46
  @config[name]
46
47
  end
47
-
48
+
48
49
  def update_config(new_config = {})
49
50
  new_config = prepare_config(new_config)
50
51
  @config = new_config
51
52
  @full_name = nil
53
+ @logger = nil
52
54
 
53
55
  debug "update config to: #{@config.inspect}"
54
56
 
@@ -57,14 +59,17 @@ module Eye::Process::Config
57
59
 
58
60
  if up?
59
61
  # rebuild checks for this process
60
- from_up; on_up
61
- end
62
+ remove_watchers
63
+ remove_childs
64
+
65
+ add_watchers
66
+ add_childs
67
+ end
62
68
  end
63
69
 
64
70
  # is pid_file under Eye::Process control, or not
65
71
  def control_pid?
66
- return self[:control_pid] unless self[:control_pid].nil?
67
72
  !!self[:daemonize]
68
73
  end
69
-
74
+
70
75
  end
@@ -52,7 +52,7 @@ module Eye::Process::Controller
52
52
  def unmonitor
53
53
  switch :unmonitoring
54
54
  end
55
-
55
+
56
56
  def delete
57
57
  if self[:stop_on_delete]
58
58
  info 'process has stop_on_delete option, so sync-stop it first'
@@ -67,10 +67,7 @@ module Eye::Process::Controller
67
67
  end
68
68
 
69
69
  def signal(sig = 0)
70
- if self.pid
71
- res = send_signal(sig)
72
- info "send signal #{sig} to #{self.pid} = #{res}"
73
- end
70
+ send_signal(sig) if self.pid
74
71
  end
75
-
72
+
76
73
  end
@@ -1,8 +1,19 @@
1
1
  module Eye::Process::Data
2
2
 
3
- # logger tag
3
+ def logger_tag
4
+ full_name
5
+ end
6
+
7
+ def app_name
8
+ self[:application]
9
+ end
10
+
11
+ def group_name
12
+ (self[:group] == '__default__') ? nil : self[:group]
13
+ end
14
+
4
15
  def full_name
5
- @full_name ||= [self[:application], (self[:group] == '__default__') ? nil : self[:group], self[:name]].compact.join(':')
16
+ @full_name ||= [app_name, group_name, self[:name]].compact.join(':')
6
17
  end
7
18
 
8
19
  def status_data(debug = false)
@@ -19,8 +30,8 @@ module Eye::Process::Data
19
30
  end
20
31
 
21
32
  def self_status_data(debug = false)
22
- h = { name: name, state: state,
23
- type: (self.class == Eye::ChildProcess ? :child_process : :process),
33
+ h = { name: name, state: state,
34
+ type: (self.class == Eye::ChildProcess ? :child_process : :process),
24
35
  resources: Eye::SystemResources.resources(pid) }
25
36
 
26
37
  if @states_history
@@ -31,7 +42,7 @@ module Eye::Process::Data
31
42
  h.merge!(debug: debug_data) if debug
32
43
  h.merge!(current_command: current_scheduled_command) if current_scheduled_command
33
44
 
34
- h
45
+ h
35
46
  end
36
47
 
37
48
  def debug_data
@@ -15,7 +15,7 @@ private
15
15
  def try_update_pid_from_file
16
16
  # if pid file was rewrited
17
17
  newpid = load_pid_from_file
18
- if newpid != self.pid
18
+ if newpid != self.pid
19
19
  info "process changed pid to #{newpid}, updating..." if self.pid
20
20
  self.pid = newpid
21
21
 
@@ -23,7 +23,7 @@ private
23
23
  return true
24
24
  else
25
25
  warn "process with new_pid #{newpid} not found"
26
- return false
26
+ return false
27
27
  end
28
28
  else
29
29
  debug 'process not found'
@@ -32,7 +32,7 @@ private
32
32
  end
33
33
 
34
34
  REWRITE_FACKUP_PIDFILE_PERIOD = 2.minutes
35
-
35
+
36
36
  def check_alive
37
37
  if up?
38
38
 
@@ -40,11 +40,13 @@ private
40
40
  unless process_realy_running?
41
41
  warn "check_alive: process(#{self.pid}) not found!"
42
42
  notify :info, 'crashed!'
43
+ clear_pid_file if control_pid? && self.pid && load_pid_from_file == self.pid
44
+
43
45
  switch :crashed, Eye::Reason.new(:crashed)
44
46
  else
45
47
  # check that pid_file still here
46
48
  ppid = failsafe_load_pid
47
-
49
+
48
50
  if ppid != self.pid
49
51
  msg = "check_alive: pid_file(#{self[:pid_file]}) changes by itself (pid:#{self.pid}) => (pid:#{ppid})"
50
52
  if control_pid?
@@ -78,7 +80,12 @@ private
78
80
  if down?
79
81
  if self[:keep_alive]
80
82
  warn 'check crashed: process is down'
81
- schedule :restore, Eye::Reason.new(:crashed)
83
+
84
+ if self[:restore_in]
85
+ schedule_in self[:restore_in].to_f, :restore, Eye::Reason.new(:crashed)
86
+ else
87
+ schedule :restore, Eye::Reason.new(:crashed)
88
+ end
82
89
  else
83
90
  warn 'check crashed: process without keep_alive'
84
91
  schedule :unmonitor, Eye::Reason.new(:crashed)