eye 0.8.pre2 → 0.8.rc

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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +141 -0
  3. data/.travis.yml +5 -3
  4. data/README.md +1 -2
  5. data/Rakefile +5 -5
  6. data/bin/leye +9 -4
  7. data/bin/loader_eye +14 -15
  8. data/examples/custom_check.eye +24 -0
  9. data/examples/custom_trigger.eye +3 -1
  10. data/examples/delayed_job.eye +3 -3
  11. data/examples/dependency.eye +10 -11
  12. data/examples/leye_example/Eyefile +10 -0
  13. data/examples/notify.eye +3 -4
  14. data/examples/plugin/main.eye +5 -5
  15. data/examples/plugin/plugin.rb +10 -2
  16. data/examples/process_thin.rb +8 -8
  17. data/examples/processes/em.rb +18 -12
  18. data/examples/processes/forking.rb +5 -5
  19. data/examples/processes/sample.rb +46 -44
  20. data/examples/puma.eye +9 -8
  21. data/examples/rbenv.eye +5 -5
  22. data/examples/sidekiq.eye +3 -3
  23. data/examples/stress_test.eye +4 -4
  24. data/examples/syslog.eye +1 -1
  25. data/examples/test.eye +1 -2
  26. data/examples/thin-farm.eye +7 -8
  27. data/examples/triggers.eye +13 -15
  28. data/examples/unicorn.eye +12 -13
  29. data/eye.gemspec +14 -12
  30. data/lib/eye.rb +2 -3
  31. data/lib/eye/application.rb +5 -6
  32. data/lib/eye/checker.rb +36 -19
  33. data/lib/eye/checker/children_count.rb +1 -1
  34. data/lib/eye/checker/file_ctime.rb +1 -1
  35. data/lib/eye/checker/http.rb +13 -15
  36. data/lib/eye/checker/nop.rb +1 -0
  37. data/lib/eye/checker/socket.rb +60 -63
  38. data/lib/eye/checker/ssl_socket.rb +5 -5
  39. data/lib/eye/child_process.rb +6 -4
  40. data/lib/eye/cli.rb +50 -41
  41. data/lib/eye/cli/commands.rb +4 -5
  42. data/lib/eye/cli/render.rb +61 -41
  43. data/lib/eye/cli/server.rb +19 -16
  44. data/lib/eye/client.rb +1 -0
  45. data/lib/eye/config.rb +19 -19
  46. data/lib/eye/controller.rb +2 -3
  47. data/lib/eye/controller/commands.rb +1 -1
  48. data/lib/eye/controller/helpers.rb +2 -2
  49. data/lib/eye/controller/load.rb +18 -12
  50. data/lib/eye/controller/options.rb +1 -5
  51. data/lib/eye/controller/send_command.rb +21 -23
  52. data/lib/eye/controller/status.rb +17 -15
  53. data/lib/eye/dsl.rb +3 -0
  54. data/lib/eye/dsl/application_opts.rb +4 -3
  55. data/lib/eye/dsl/chain.rb +2 -2
  56. data/lib/eye/dsl/child_process_opts.rb +3 -3
  57. data/lib/eye/dsl/config_opts.rb +7 -7
  58. data/lib/eye/dsl/group_opts.rb +3 -3
  59. data/lib/eye/dsl/helpers.rb +1 -1
  60. data/lib/eye/dsl/main.rb +4 -3
  61. data/lib/eye/dsl/opts.rb +31 -28
  62. data/lib/eye/dsl/process_opts.rb +13 -7
  63. data/lib/eye/dsl/pure_opts.rb +13 -9
  64. data/lib/eye/dsl/validation.rb +48 -35
  65. data/lib/eye/group.rb +20 -6
  66. data/lib/eye/group/chain.rb +6 -6
  67. data/lib/eye/loader.rb +1 -1
  68. data/lib/eye/local.rb +9 -4
  69. data/lib/eye/logger.rb +11 -4
  70. data/lib/eye/notify.rb +10 -6
  71. data/lib/eye/notify/jabber.rb +1 -1
  72. data/lib/eye/notify/mail.rb +2 -2
  73. data/lib/eye/notify/slack.rb +4 -3
  74. data/lib/eye/process.rb +2 -0
  75. data/lib/eye/process/children.rb +4 -4
  76. data/lib/eye/process/commands.rb +28 -31
  77. data/lib/eye/process/config.rb +21 -19
  78. data/lib/eye/process/data.rb +11 -9
  79. data/lib/eye/process/monitor.rb +30 -29
  80. data/lib/eye/process/notify.rb +10 -10
  81. data/lib/eye/process/scheduler.rb +36 -31
  82. data/lib/eye/process/states.rb +5 -4
  83. data/lib/eye/process/states_history.rb +9 -3
  84. data/lib/eye/process/system.rb +5 -4
  85. data/lib/eye/process/trigger.rb +1 -5
  86. data/lib/eye/process/watchers.rb +6 -9
  87. data/lib/eye/reason.rb +4 -1
  88. data/lib/eye/server.rb +2 -1
  89. data/lib/eye/system.rb +16 -13
  90. data/lib/eye/system_resources.rb +13 -8
  91. data/lib/eye/trigger.rb +18 -16
  92. data/lib/eye/trigger/check_dependency.rb +7 -4
  93. data/lib/eye/trigger/flapping.rb +24 -7
  94. data/lib/eye/trigger/starting_guard.rb +7 -6
  95. data/lib/eye/trigger/stop_children.rb +2 -2
  96. data/lib/eye/trigger/transition.rb +1 -1
  97. data/lib/eye/trigger/wait_dependency.rb +3 -2
  98. data/lib/eye/utils.rb +4 -3
  99. data/lib/eye/utils/alive_array.rb +9 -4
  100. data/lib/eye/utils/celluloid_chain.rb +12 -10
  101. data/lib/eye/utils/mini_active_support.rb +16 -16
  102. data/lib/eye/utils/pmap.rb +2 -0
  103. data/lib/eye/utils/tail.rb +2 -2
  104. metadata +34 -4
  105. data/lib/eye/utils/leak_19.rb +0 -10
@@ -5,21 +5,21 @@ module Eye::Process::Notify
5
5
  # 2) checker bounded to restart process [:warn]
6
6
  # 3) flapping + switch to unmonitored [:error]
7
7
 
8
- LEVELS = {:debug => 0, :info => 1, :warn => 2, :error => 3, :fatal => 4}
8
+ LEVELS = { debug: 0, info: 1, warn: 2, error: 3, fatal: 4 }
9
9
 
10
10
  def notify(level, msg)
11
11
  # logging it
12
12
  error "NOTIFY: #{msg}" if ilevel(level) > ilevel(:info)
13
13
 
14
+ return if self[:notify].blank?
15
+
14
16
  # send notifies
15
- if self[:notify].present?
16
- message = {:message => msg, :name => name,
17
- :full_name => full_name, :pid => pid, :host => Eye::Local.host, :level => level,
18
- :at => Time.now }
19
-
20
- self[:notify].each do |contact, not_level|
21
- Eye::Notify.notify(contact, message) if ilevel(level) >= ilevel(not_level)
22
- end
17
+ message = { message: msg, name: name,
18
+ full_name: full_name, pid: pid, host: Eye::Local.host, level: level,
19
+ at: Time.now }
20
+
21
+ self[:notify].each do |contact, not_level|
22
+ Eye::Notify.notify(contact, message) if ilevel(level) >= ilevel(not_level)
23
23
  end
24
24
  end
25
25
 
@@ -29,4 +29,4 @@ private
29
29
  LEVELS[level].to_i
30
30
  end
31
31
 
32
- end
32
+ end
@@ -2,32 +2,30 @@ module Eye::Process::Scheduler
2
2
 
3
3
  # ex: schedule :update_config, config, "reason: update_config"
4
4
  def schedule(command, *args, &block)
5
- if scheduler.alive?
6
- if scheduler_freeze?
7
- warn ":#{command} ignoring to schedule, because scheduler is freeze"
8
- return
9
- end
10
-
11
- unless self.respond_to?(command, true)
12
- warn ":#{command} scheduling is unsupported"
13
- return
14
- end
15
-
16
- reason = if args.present? && args[-1].kind_of?(Eye::Reason)
17
- args.pop
18
- end
19
-
20
- info "schedule :#{command} #{reason ? "(reason: #{reason})" : nil}"
21
-
22
- if reason.class == Eye::Reason
23
- # for auto reasons
24
- # skip already running commands and all in chain
25
- scheduler.add_wo_dups_current(:scheduled_action, command, {:args => args, :reason => reason}, &block)
26
- else
27
- # for manual, or without reason
28
- # skip only for last in chain
29
- scheduler.add_wo_dups(:scheduled_action, command, {:args => args, :reason => reason}, &block)
30
- end
5
+ return unless scheduler.alive?
6
+
7
+ if scheduler_freeze?
8
+ warn ":#{command} ignoring to schedule, because scheduler is freeze"
9
+ return
10
+ end
11
+
12
+ unless self.respond_to?(command, true)
13
+ warn ":#{command} scheduling is unsupported"
14
+ return
15
+ end
16
+
17
+ reason = args.pop if args.present? && args[-1].is_a?(Eye::Reason)
18
+
19
+ info "schedule :#{command} #{reason ? "(reason: #{reason})" : nil}"
20
+
21
+ if reason.class == Eye::Reason
22
+ # for auto reasons
23
+ # skip already running commands and all in chain
24
+ scheduler.add_wo_dups_current(:scheduled_action, command, args: args, reason: reason, block: block)
25
+ else
26
+ # for manual, or without reason
27
+ # skip only for last in chain
28
+ scheduler.add_wo_dups(:scheduled_action, command, args: args, reason: reason, block: block)
31
29
  end
32
30
  end
33
31
 
@@ -39,16 +37,16 @@ module Eye::Process::Scheduler
39
37
  end
40
38
  end
41
39
 
42
- def scheduled_action(command, h = {}, &block)
43
- reason = h.delete(:reason)
44
- info "=> #{command} #{h[:args].present? ? "#{h[:args]*',' }" : nil} #{reason ? "(reason: #{reason})" : nil}"
40
+ def scheduled_action(command, h = {})
41
+ reason = h[:reason]
42
+ info "=> #{command} #{h[:args].present? ? "#{h[:args] * ','}" : nil} #{reason ? "(reason: #{reason})" : nil}"
45
43
 
46
44
  @current_scheduled_command = command
47
45
  @last_scheduled_command = command
48
46
  @last_scheduled_reason = reason
49
47
  @last_scheduled_at = Time.now
50
48
 
51
- send(command, *h[:args], &block)
49
+ send(command, *h[:args], &h[:block])
52
50
  @current_scheduled_command = nil
53
51
  info "<= #{command}"
54
52
 
@@ -59,8 +57,14 @@ module Eye::Process::Scheduler
59
57
  end
60
58
  end
61
59
 
60
+ def execute_proc(*_args, &block)
61
+ self.instance_exec(&block)
62
+ rescue Object => ex
63
+ log_ex(ex)
64
+ end
65
+
62
66
  def scheduler_actions_list
63
- scheduler.list.map{|c| c[:args].first rescue nil }.compact
67
+ scheduler.list.map { |c| c[:args].first rescue nil }.compact
64
68
  end
65
69
 
66
70
  def scheduler_clear_pending_list
@@ -69,6 +73,7 @@ module Eye::Process::Scheduler
69
73
 
70
74
  def self.included(base)
71
75
  base.finalizer :remove_scheduler
76
+ base.execute_block_on_receiver :schedule
72
77
  end
73
78
 
74
79
  attr_accessor :current_scheduled_command
@@ -2,6 +2,7 @@ require 'state_machine'
2
2
  require 'state_machine/version'
3
3
 
4
4
  class Eye::Process
5
+
5
6
  class StateError < Exception; end
6
7
 
7
8
  # do transition
@@ -59,10 +60,10 @@ class Eye::Process
59
60
 
60
61
  after_transition any => :unmonitored, :do => :on_unmonitored
61
62
 
62
- after_transition any-:up => :up, :do => :add_watchers
63
- after_transition :up => any-:up, :do => :remove_watchers
63
+ after_transition any - :up => :up, :do => :add_watchers
64
+ after_transition :up => any - :up, :do => :remove_watchers
64
65
 
65
- after_transition any-:up => :up, :do => :add_children
66
+ after_transition any - :up => :up, :do => :add_children
66
67
  after_transition any => [:unmonitored, :down], :do => :remove_children
67
68
 
68
69
  after_transition :on => :crashed, :do => :on_crashed
@@ -80,7 +81,7 @@ class Eye::Process
80
81
  def log_transition(transition)
81
82
  if transition.to_name != transition.from_name || @state_reason.is_a?(Eye::Reason::User)
82
83
  @states_history.push transition.to_name, @state_reason
83
- info "switch :#{transition.event} [:#{transition.from_name} => :#{transition.to_name}] #{@state_reason ? "(reason: #{@state_reason})" : nil}"
84
+ info "switch :#{transition.event} [:#{transition.from_name} => :#{transition.to_name}] #{"(reason: #{@state_reason})" if @state_reason}"
84
85
  end
85
86
  end
86
87
 
@@ -1,17 +1,22 @@
1
1
  class Eye::Process::StatesHistory < Eye::Utils::Tail
2
+
2
3
  def push(state, reason = nil, tm = Time.now)
3
4
  super(state: state, at: tm.to_i, reason: reason)
4
5
  end
5
6
 
6
7
  def states
7
- self.map{|c| c[:state] }
8
+ self.map { |c| c[:state] }
8
9
  end
9
10
 
10
- def states_for_period(period, from_time = nil)
11
+ def states_for_period(period, from_time = nil, &block)
11
12
  tm = Time.now - period
12
13
  tm = [tm, from_time].max if from_time
13
14
  tm = tm.to_f
14
- self.select{|s| s[:at] >= tm }.map{|c| c[:state] }
15
+ if block
16
+ self.each { |s| block.call(s) if s[:at] >= tm }
17
+ else
18
+ self.select { |s| s[:at] >= tm }.map { |c| c[:state] }
19
+ end
15
20
  end
16
21
 
17
22
  def last_state
@@ -25,4 +30,5 @@ class Eye::Process::StatesHistory < Eye::Utils::Tail
25
30
  def last_state_changed_at
26
31
  Time.at(last[:at])
27
32
  end
33
+
28
34
  end
@@ -46,7 +46,8 @@ module Eye::Process::System
46
46
  st1 = st.to_i
47
47
  id1 = id.to_i
48
48
  if (id1 - st1).abs > self[:check_identity_grace]
49
- msg = "pid_file: '#{Eye::Utils.human_time2(id)}', process: '#{Eye::Utils.human_time2(st)}' (#{Eye::SystemResources.args(pid)})"
49
+ args = Eye::SystemResources.args(pid)
50
+ msg = "pid_file: '#{Eye::Utils.human_time2(id)}', process: '#{Eye::Utils.human_time2(st)}' (#{args})"
50
51
  res = (id1 < st1) ? :fail : :touched
51
52
  warn "compare_identity: #{res}, #{msg}"
52
53
  res
@@ -75,7 +76,7 @@ module Eye::Process::System
75
76
  res[:result] == :ok
76
77
  end
77
78
 
78
- def wait_for_condition(timeout, step = 0.1, &block)
79
+ def wait_for_condition(timeout, step = 0.1, &_block)
79
80
  res = nil
80
81
  sumtime = 0
81
82
 
@@ -90,7 +91,7 @@ module Eye::Process::System
90
91
  end
91
92
 
92
93
  def execute(cmd, cfg = {})
93
- defer { Eye::System::execute cmd, cfg }.tap do |res|
94
+ defer { Eye::System.execute cmd, cfg }.tap do |res|
94
95
  notify(:debug, "Bad exit status of command #{cmd.inspect}(#{res[:exitstatus].inspect})") if res[:exitstatus] != 0
95
96
  end
96
97
  end
@@ -99,7 +100,7 @@ module Eye::Process::System
99
100
  Eye::System.daemonize(cmd, cfg)
100
101
  end
101
102
 
102
- def execute_sync(cmd, opts = {:timeout => 1.second})
103
+ def execute_sync(cmd, opts = { timeout: 1.second })
103
104
  execute(cmd, self.config.merge(opts)).tap do |res|
104
105
  info "execute_sync `#{cmd}` with res: #{res}"
105
106
  end
@@ -1,11 +1,7 @@
1
1
  module Eye::Process::Trigger
2
2
 
3
3
  def add_triggers
4
- if self[:triggers]
5
- self[:triggers].each do |type, cfg|
6
- add_trigger(cfg)
7
- end
8
- end
4
+ (self[:triggers] || {}).each { |_type, cfg| add_trigger(cfg) }
9
5
  end
10
6
 
11
7
  def remove_triggers
@@ -32,7 +32,7 @@ module Eye::Process::Watchers
32
32
  end
33
33
 
34
34
  def remove_watchers
35
- @watchers.each{|_, h| h[:timer].cancel }
35
+ @watchers.each { |_, h| h[:timer].cancel }
36
36
  @watchers = {}
37
37
  end
38
38
 
@@ -48,25 +48,22 @@ private
48
48
  block.call(subject)
49
49
  end
50
50
 
51
- @watchers[type] ||= {:timer => timer, :subject => subject}
51
+ @watchers[type] ||= { timer: timer, subject: subject }
52
52
  end
53
53
 
54
54
  def start_checkers
55
- self[:checks].each{|name, cfg| start_checker(name, cfg) }
55
+ self[:checks].each { |name, cfg| start_checker(name, cfg) }
56
56
  end
57
57
 
58
58
  def start_checker(name, cfg)
59
+ # cfg: {:type => :memory, :every => 5.seconds, :below => 100.megabytes, :times => [3, 5]}
59
60
  subject = Eye::Checker.create(pid, cfg, current_actor)
60
-
61
- # ex: {:type => :memory, :every => 5.seconds, :below => 100.megabytes, :times => [3,5]}
62
61
  add_watcher("check_#{name}".to_sym, subject.every, subject, &method(:watcher_tick).to_proc) if subject
63
62
  end
64
63
 
65
64
  def watcher_tick(subject)
66
- unless subject.check
67
- return unless up?
68
- subject.fire
69
- end
65
+ # double up? test needed because state can changed while subject.check
66
+ subject.fire if up? && !subject.check && up?
70
67
  end
71
68
 
72
69
  end
@@ -13,11 +13,14 @@ class Eye::Reason
13
13
  end
14
14
 
15
15
  class User < Eye::Reason
16
+
16
17
  def to_s
17
18
  "#{super} by user"
18
19
  end
20
+
19
21
  end
20
22
 
21
23
  class Flapping < Eye::Reason; end
22
24
  class StartingGuard < Eye::Reason; end
23
- end
25
+
26
+ end
@@ -1,7 +1,8 @@
1
- require 'celluloid/io'
2
1
  require 'celluloid/current'
2
+ require 'celluloid/io'
3
3
 
4
4
  class Eye::Server
5
+
5
6
  include Celluloid::IO
6
7
 
7
8
  attr_reader :socket_path, :server
@@ -3,7 +3,9 @@ require 'etc'
3
3
  require 'timeout'
4
4
 
5
5
  module Eye::System
6
+
6
7
  class << self
8
+
7
9
  # Check that pid really exits
8
10
  # very fast
9
11
  # return result hash
@@ -14,9 +16,9 @@ module Eye::System
14
16
  false
15
17
  end
16
18
 
17
- {:result => res}
19
+ { result: res }
18
20
  rescue => ex
19
- {:error => ex}
21
+ { error: ex }
20
22
  end
21
23
 
22
24
  # Check that pid really exits
@@ -39,13 +41,13 @@ module Eye::System
39
41
 
40
42
  if pid
41
43
  ::Process.kill(code, pid)
42
- {:result => :ok}
44
+ { result: :ok }
43
45
  else
44
- {:error => Exception.new('no_pid')}
46
+ { error: Exception.new('no_pid') }
45
47
  end
46
48
 
47
49
  rescue => ex
48
- {:error => ex}
50
+ { error: ex }
49
51
  end
50
52
 
51
53
  # Daemonize cmd, and detach
@@ -55,12 +57,12 @@ module Eye::System
55
57
  # :environment
56
58
  # :stdin, :stdout, :stderr
57
59
  def daemonize(cmd, cfg = {})
58
- pid = ::Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))
60
+ pid = ::Process.spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))
59
61
 
60
- {:pid => pid, :exitstatus => 0}
62
+ { pid: pid, exitstatus: 0 }
61
63
 
62
64
  rescue Errno::ENOENT, Errno::EACCES => ex
63
- {:error => ex}
65
+ { error: ex }
64
66
 
65
67
  ensure
66
68
  Process.detach(pid) if pid
@@ -72,7 +74,7 @@ module Eye::System
72
74
  # :environment
73
75
  # :stdin, :stdout, :stderr
74
76
  def execute(cmd, cfg = {})
75
- pid = ::Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))
77
+ pid = ::Process.spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))
76
78
 
77
79
  timeout = cfg[:timeout] || 1.second
78
80
  status = 0
@@ -82,17 +84,17 @@ module Eye::System
82
84
  status = st.exitstatus || st.termsig
83
85
  end
84
86
 
85
- {:pid => pid, :exitstatus => status}
87
+ { pid: pid, exitstatus: status }
86
88
 
87
89
  rescue Timeout::Error => ex
88
90
  if pid
89
91
  warn "[#{cfg[:name]}] sending :KILL signal to <#{pid}> due to timeout (#{timeout}s)"
90
92
  send_signal(pid, 9)
91
93
  end
92
- {:error => ex}
94
+ { error: ex }
93
95
 
94
96
  rescue Errno::ENOENT, Errno::EACCES => ex
95
- {:error => ex}
97
+ { error: ex }
96
98
 
97
99
  ensure
98
100
  Process.detach(pid) if pid
@@ -127,12 +129,13 @@ module Eye::System
127
129
  def prepare_env(config = {})
128
130
  env = {}
129
131
 
130
- (config[:environment] || {}).each do |k,v|
132
+ (config[:environment] || {}).each do |k, v|
131
133
  env[k.to_s] = v && v.to_s
132
134
  end
133
135
 
134
136
  env
135
137
  end
138
+
136
139
  end
137
140
 
138
141
  end
@@ -45,7 +45,7 @@ class Eye::SystemResources
45
45
  end
46
46
 
47
47
  def deep_children(pid)
48
- Array(pid_or_children(pid)).flatten.sort_by { |pid| -pid }
48
+ Array(pid_or_children(pid)).flatten.sort_by(&:-@)
49
49
  end
50
50
 
51
51
  def pid_or_children(pid)
@@ -62,19 +62,20 @@ class Eye::SystemResources
62
62
  end
63
63
 
64
64
  def resources(pid)
65
- { :memory => memory(pid),
66
- :cpu => cpu(pid),
67
- :start_time => start_time(pid),
68
- :pid => pid
69
- }
65
+ { memory: memory(pid),
66
+ cpu: cpu(pid),
67
+ start_time: start_time(pid),
68
+ pid: pid }
70
69
  end
71
70
 
72
71
  def cache
73
72
  Celluloid::Actor[:system_resources_cache]
74
73
  end
74
+
75
75
  end
76
76
 
77
77
  class Cache
78
+
78
79
  include Celluloid
79
80
 
80
81
  attr_reader :expire
@@ -99,13 +100,15 @@ class Eye::SystemResources
99
100
  def proc_mem(pid)
100
101
  @memory[pid] ||= Eye::Sigar.proc_mem(pid) if pid
101
102
 
102
- rescue ArgumentError # when incorrect PID
103
+ rescue ArgumentError
104
+ # when incorrect PID, just skip
103
105
  end
104
106
 
105
107
  def proc_cpu(pid)
106
108
  @cpu[pid] ||= Eye::Sigar.proc_cpu(pid) if pid
107
109
 
108
- rescue ArgumentError # when incorrect PID
110
+ rescue ArgumentError
111
+ # when incorrect PID, just skip
109
112
  end
110
113
 
111
114
  def children(pid)
@@ -115,8 +118,10 @@ class Eye::SystemResources
115
118
  []
116
119
  end
117
120
  end
121
+
118
122
  end
119
123
 
120
124
  # Setup global sigar singleton here
121
125
  Cache.supervise(as: :system_resources_cache)
126
+
122
127
  end