eye 0.6.4 → 0.7.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1efc0c3530c9b3015f9a7b6a536e12d9c8221189
4
- data.tar.gz: 012ddf11788989c1d13cb1bd766d95c9a3da3fd2
3
+ metadata.gz: 488ed21561da07936dd5fbc3e0d869e4665ba4a5
4
+ data.tar.gz: 12b6d6c69ee5e0bf9409bb61e700a6525d1d386a
5
5
  SHA512:
6
- metadata.gz: 9b57ada510bfd95fb8402c08efc2a983b27102916e869e3e16da52faed26aa53154eec0bf685c9005dea68386b451b412b92c6190fd536449aeeaf59738aeae5
7
- data.tar.gz: ff9c785da7173b427c7cb071d7cedc399d5698b38a8eed8810eeff9521ade37cf400359d16a3605248f4f8b6f91f9c15791ef042965045ec4732ed597303d1b7
6
+ metadata.gz: 54a0993fb03ecf29c9f8a572c977aeb6856da53b972f6d3555c1e17fef13bc807fdfb819ed968f4571f5ee3dd05c8faf0cf766a77be6017ac81e007927605438
7
+ data.tar.gz: 3023586158006d3c76ba25675b88bfc2eb0977cafc748b928437ab1cf74178d4494e229e6028615ae8c1efc667188566b0801f5739fa565a94026e6cd737fb56
data/.travis.yml CHANGED
@@ -4,4 +4,4 @@ rvm:
4
4
  - "2.0.0"
5
5
  - "2.1"
6
6
  - "2.2"
7
- script: bundle exec rake N=15
7
+ script: bundle exec rake split_test N=15
data/CHANGES.md CHANGED
@@ -1,5 +1,10 @@
1
1
  0.7.pre
2
2
  -------
3
+ * add trigger starting_guard
4
+ * fix multiple contacts #118
5
+ * add slack notifier #115
6
+ * some fixes in depend_on
7
+ * some fixes in flapping
3
8
  * Update Celluloid to 0.16.0
4
9
 
5
10
  0.6.4
data/Gemfile CHANGED
@@ -1,6 +1,2 @@
1
1
  source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in eye.gemspec
4
2
  gemspec
5
-
6
- gem 'parallel_tests', :git => "https://github.com/kostya/parallel_tests.git"
data/README.md CHANGED
@@ -28,7 +28,7 @@ I hope we've succeeded, we're using eye in production and are quite happy.
28
28
 
29
29
  ### Config example
30
30
 
31
- examples/test.eye
31
+ examples/test.eye ([more examples](https://github.com/kostya/eye/tree/master/examples))
32
32
  ```ruby
33
33
  # load submodules, here just for example
34
34
  Eye.load('./eye/*.rb')
@@ -200,16 +200,23 @@ Eye daemon info:
200
200
  $ eye x(info)
201
201
  $ eye x -c # for show current config
202
202
 
203
+ Local Eye version LEye (like foreman):
204
+
205
+ [LEye](https://github.com/kostya/eye/wiki/What-is-loader_eye-and-leye)
206
+
203
207
  Process states and events:
204
208
 
205
209
  [![Eye](https://raw.github.com/kostya/stuff/master/eye/mprocess.png)](https://raw.github.com/kostya/stuff/master/eye/process.png)
206
210
 
211
+ How to write Eye extensions, plugins, gems:
212
+
213
+ [Eye-http](https://github.com/kostya/eye-http) [Eye-rotate](https://github.com/kostya/eye-rotate) [Eye-hipchat](https://github.com/tmeinlschmidt/eye-hipchat) [Plugin example](https://github.com/kostya/eye/tree/master/examples/plugin)
207
214
 
208
215
  [Eye related projects](https://github.com/kostya/eye/wiki/Related-projects)
209
216
 
210
217
  [Articles](https://github.com/kostya/eye/wiki/Articles)
211
218
 
212
- [Using Env variables](https://github.com/kostya/eye/wiki/Using-ENV-variables-in-config)
219
+ [Wiki](https://github.com/kostya/eye/wiki)
213
220
 
214
221
 
215
222
  Thanks `Bluepill` for the nice config ideas.
data/Rakefile CHANGED
@@ -2,15 +2,25 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  require 'rspec/core/rake_task'
5
- require 'parallel_tests/tasks'
6
5
  require 'coveralls/rake/task'
7
6
 
8
7
  Coveralls::RakeTask.new
9
8
 
10
9
  task :default => :pspec
11
10
 
11
+ desc "run parallel tests"
12
12
  task :pspec do
13
- Rake::Task['parallel:spec'].invoke(ENV['N'] || 10)
13
+ dirname = File.expand_path(File.dirname(__FILE__))
14
+ cmd = "bundle exec parallel_rspec -n #{ENV['N'] || 10} --runtime-log '#{dirname}/spec/weights.txt' #{dirname}/spec"
15
+ abort unless system(cmd)
16
+ end
17
+
18
+ desc "run parallel split tests"
19
+ task :split_test do
20
+ dirname = File.expand_path(File.dirname(__FILE__))
21
+ ENV['PARALLEL_SPLIT_TEST_PROCESSES'] = (ENV['N'] || 10).to_s
22
+ cmd = "bundle exec parallel_split_test #{dirname}/spec"
23
+ abort unless system(cmd)
14
24
  end
15
25
 
16
26
  RSpec::Core::RakeTask.new(:spec) do |t|
@@ -14,4 +14,25 @@ Eye.app :dependency do
14
14
  depend_on :a
15
15
  end
16
16
 
17
+ process(:c) do
18
+ start_command "sleep 100"
19
+ daemonize true
20
+ pid_file "/tmp/test_process_c.pid"
21
+ depend_on :a
22
+ end
23
+
24
+ process(:d) do
25
+ start_command "sleep 100"
26
+ daemonize true
27
+ pid_file "/tmp/test_process_d.pid"
28
+ depend_on :b
29
+ end
30
+
31
+ process(:e) do
32
+ start_command "sleep 100"
33
+ daemonize true
34
+ pid_file "/tmp/test_process_e.pid"
35
+ depend_on [:d, :c]
36
+ end
37
+
17
38
  end
@@ -1,6 +1,6 @@
1
1
  # this is not example, just config for eye stress test
2
2
 
3
- PREFIX = ENV['PRE'] || 1
3
+ PREFIX = ENV['PRE'] || ENV['EYE_V'] || 1
4
4
 
5
5
  Eye.app :stress_test do
6
6
  working_dir "/tmp"
@@ -52,4 +52,13 @@ Eye.app :triggers do
52
52
  }
53
53
  end
54
54
 
55
+ # process d cant start, until file /tmp/bla contains string 'bla'
56
+ process :d do
57
+ pid_file "/tmp/d.pid"
58
+ start_command "sleep 100"
59
+ daemonize true
60
+
61
+ trigger :starting_guard, every: 5.seconds, should: -> { `cat /tmp/bla` =~ /bla/ }
62
+ end
63
+
55
64
  end
data/eye.gemspec CHANGED
@@ -19,8 +19,8 @@ Gem::Specification.new do |gem|
19
19
  gem.required_ruby_version = '>= 1.9.2'
20
20
  gem.required_rubygems_version = '>= 1.3.6'
21
21
 
22
- gem.add_dependency 'celluloid', '~> 0.15.0'
23
- gem.add_dependency 'celluloid-io', '~> 0.15.0'
22
+ gem.add_dependency 'celluloid', '~> 0.16.0'
23
+ gem.add_dependency 'celluloid-io', '~> 0.16.0'
24
24
  gem.add_dependency 'state_machine'
25
25
  gem.add_dependency 'thor'
26
26
  gem.add_dependency 'sigar', '~> 0.7.2'
@@ -35,6 +35,9 @@ Gem::Specification.new do |gem|
35
35
  gem.add_development_dependency 'sinatra'
36
36
  gem.add_development_dependency 'thin'
37
37
  gem.add_development_dependency 'xmpp4r'
38
+ gem.add_development_dependency 'slack-notifier'
38
39
  gem.add_development_dependency 'coveralls'
39
40
  gem.add_development_dependency 'simplecov', '>= 0.8.1'
41
+ gem.add_development_dependency 'parallel_tests', '<= 1.3.1'
42
+ gem.add_development_dependency 'parallel_split_test'
40
43
  end
data/lib/eye.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Eye
2
- VERSION = "0.6.4"
2
+ VERSION = "0.7.pre"
3
3
  ABOUT = "Eye v#{VERSION} (c) 2012-2015 @kostya"
4
4
  PROCLINE = "eye monitoring v#{VERSION}"
5
5
 
@@ -6,6 +6,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
6
6
  # :url => "http://127.0.0.1:3000/", :kind => :success, :pattern => /OK/, :timeout => 3.seconds
7
7
 
8
8
  param :url, String, true
9
+ param :proxy_url, String
9
10
  param :pattern, [String, Regexp]
10
11
  param :kind, [String, Fixnum, Symbol]
11
12
  param :timeout, [Fixnum, Float]
@@ -18,6 +19,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
18
19
  super
19
20
 
20
21
  @uri = URI.parse(url)
22
+ @proxy_uri = URI.parse(proxy_url) if proxy_url
21
23
  @kind = case kind
22
24
  when Fixnum then Net::HTTPResponse::CODE_TO_OBJ[kind]
23
25
  when String, Symbol then Net.const_get("HTTP#{kind.to_s.camelize}") rescue Net::HTTPSuccess
@@ -82,15 +84,23 @@ class Eye::Checker::Http < Eye::Checker::Defer
82
84
  private
83
85
 
84
86
  def session
85
- Net::HTTP.new(@uri.host, @uri.port).tap do |session|
87
+ net_http.tap do |session|
86
88
  if @uri.scheme == 'https'
87
89
  require 'net/https'
88
90
  session.use_ssl = true
89
91
  session.verify_mode = OpenSSL::SSL::VERIFY_NONE
90
92
  end
93
+
91
94
  session.open_timeout = @open_timeout
92
95
  session.read_timeout = @read_timeout
93
96
  end
94
97
  end
95
98
 
99
+ def net_http
100
+ if @proxy_uri
101
+ Net::HTTP.new(@uri.host, @uri.port, @proxy_uri.host, @proxy_uri.port)
102
+ else
103
+ Net::HTTP.new(@uri.host, @uri.port)
104
+ end
105
+ end
96
106
  end
data/lib/eye/config.rb CHANGED
@@ -8,11 +8,14 @@ class Eye::Config
8
8
  end
9
9
 
10
10
  def merge(other_config)
11
- Eye::Config.new(@settings.merge(other_config.settings), @applications.merge(other_config.applications))
11
+ new_settings = {}
12
+ Eye::Utils.deep_merge!(new_settings, @settings)
13
+ Eye::Utils.deep_merge!(new_settings, other_config.settings)
14
+ Eye::Config.new(new_settings, @applications.merge(other_config.applications))
12
15
  end
13
16
 
14
17
  def merge!(other_config)
15
- @settings.merge!(other_config.settings)
18
+ Eye::Utils.deep_merge!(@settings, other_config.settings)
16
19
  @applications.merge!(other_config.applications)
17
20
  end
18
21
 
@@ -10,7 +10,9 @@ require_relative 'utils/mini_active_support'
10
10
  # Extend all objects with logger
11
11
  Object.send(:include, Eye::Logger::ObjectExt)
12
12
 
13
- Eye::Sigar # needs to preload
13
+ # needs to preload
14
+ Eye::Sigar
15
+ Eye::SystemResources
14
16
 
15
17
  class Eye::Controller
16
18
  include Celluloid
@@ -36,7 +38,6 @@ class Eye::Controller
36
38
  @current_config = Eye::Config.new
37
39
 
38
40
  Celluloid::logger = Eye::Logger.new('celluloid')
39
- Eye::SystemResources.cache
40
41
 
41
42
  info "starting #{Eye::ABOUT} <#{$$}>"
42
43
  end
@@ -75,6 +75,7 @@ private
75
75
  exclusive do
76
76
  send_command :break_chain, 'all'
77
77
  send_command :stop, 'all'
78
+ send_command :freeze, 'all'
78
79
  end
79
80
 
80
81
  # wait until all processes goes to unmonitored
data/lib/eye/dsl/main.rb CHANGED
@@ -55,4 +55,9 @@ module Eye::Dsl::Main
55
55
 
56
56
  alias settings config
57
57
 
58
+ def shared
59
+ require 'ostruct'
60
+ @shared_object ||= OpenStruct.new
61
+ end
62
+
58
63
  end
data/lib/eye/dsl/opts.rb CHANGED
@@ -196,15 +196,13 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
196
196
  end
197
197
  raise Eye::Dsl::Error, "load_env conflict filenames: #{filenames}" if filenames.size > 1
198
198
 
199
- content = File.read(filenames.first)
200
199
  info "load_env from '#{filenames.first}'"
200
+ Eye::Utils.load_env(filenames.first).each { |k, v| env k => v }
201
+ end
201
202
 
202
- env_vars = content.split("\n")
203
- env_vars.each do |e|
204
- next unless e.include?('=')
205
- k, *v = e.split('=')
206
- env k => v.join('=')
207
- end
203
+ def skip_group_action(act, val = true)
204
+ @config[:skip_group_actions] ||= {}
205
+ @config[:skip_group_actions][act] = val
208
206
  end
209
207
 
210
208
  private
@@ -24,6 +24,8 @@ class Eye::Dsl::ProcessOpts < Eye::Dsl::Opts
24
24
  trigger("check_dependency_#{unique_num}", :names => [ nm ] )
25
25
  end
26
26
  end
27
+
28
+ skip_group_action(:restart, [:up, :down, :starting, :stopping, :restarting])
27
29
  end
28
30
 
29
31
  private
@@ -32,7 +32,7 @@ module Eye::Dsl::Validation
32
32
 
33
33
  define_method "#{param}" do
34
34
  value = @options[param]
35
- value.nil? ? default : value
35
+ value.nil? ? self.class.defaults[param] : value
36
36
  end
37
37
 
38
38
  define_method "#{param}=" do |value|
@@ -89,4 +89,4 @@ module Eye::Dsl::Validation
89
89
  end
90
90
  end
91
91
 
92
- end
92
+ end
data/lib/eye/group.rb CHANGED
@@ -123,6 +123,10 @@ class Eye::Group
123
123
  @chain_breaker = true
124
124
  end
125
125
 
126
+ def freeze
127
+ async_schedule :freeze
128
+ end
129
+
126
130
  def clear
127
131
  @processes = Eye::Utils::AliveArray.new
128
132
  end
@@ -137,7 +141,7 @@ private
137
141
  info "send to all processes #{command} #{args.present? ? args*',' : nil}"
138
142
 
139
143
  @processes.each do |process|
140
- process.send_command(command, *args)
144
+ process.send_command(command, *args) unless process.skip_group_action?(command)
141
145
  end
142
146
  end
143
147
 
@@ -12,6 +12,11 @@ private
12
12
  started_at = Time.now
13
13
 
14
14
  @processes.each do | process |
15
+ if process.skip_group_action?(command)
16
+ @chain_processes_current = @chain_processes_current.to_i + 1
17
+ next
18
+ end
19
+
15
20
  chain_schedule_process(process, type, command, *args)
16
21
 
17
22
  @chain_processes_current = @chain_processes_current.to_i + 1
data/lib/eye/loader.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # add gems to $: by `gem` method
2
2
  # this is only way when install eye as system wide
3
3
 
4
- gem 'celluloid', '~> 0.15.0'
5
- gem 'celluloid-io', '~> 0.15.0'
4
+ gem 'celluloid', '~> 0.16.0'
5
+ gem 'celluloid-io', '~> 0.16.0'
6
6
  gem 'nio4r'
7
7
  gem 'timers'
8
8
 
data/lib/eye/notify.rb CHANGED
@@ -6,8 +6,9 @@ class Eye::Notify
6
6
 
7
7
  autoload :Mail, 'eye/notify/mail'
8
8
  autoload :Jabber, 'eye/notify/jabber'
9
+ autoload :Slack, 'eye/notify/slack'
9
10
 
10
- TYPES = {:mail => 'Mail', :jabber => 'Jabber'}
11
+ TYPES = {:mail => 'Mail', :jabber => 'Jabber', :slack => 'Slack'}
11
12
 
12
13
  def self.get_class(type)
13
14
  klass = eval("Eye::Notify::#{TYPES[type]}") rescue nil
@@ -0,0 +1,38 @@
1
+ require 'slack-notifier'
2
+
3
+ class Eye::Notify::Slack < Eye::Notify
4
+
5
+ # Eye.config do
6
+ # slack :webhook_url => "http://...", :channel => "#default", :username => "eye"
7
+ # contact :channel, :slack, "@channel"
8
+ # end
9
+
10
+ param :webhook_url, String, true
11
+ param :channel, String, nil, "#default"
12
+ param :username, String, nil, "eye"
13
+
14
+ param :icon, String
15
+
16
+ def execute
17
+ debug { "send slack #{[channel, username]} - #{[contact, message_body]}" }
18
+
19
+ options = {
20
+ channel: channel,
21
+ username: username
22
+ }
23
+
24
+ options[:icon_emoji] = icon if icon && icon.start_with?(':')
25
+ options[:icon_url] = icon if icon && icon.start_with?('http')
26
+
27
+ notifier = ::Slack::Notifier.new webhook_url, options
28
+
29
+ notifier.ping message_body
30
+ end
31
+
32
+ def message_body
33
+ payload = ''
34
+ payload << "#{contact}: *#{msg_host}* _#{msg_full_name}_ at #{Eye::Utils.human_time2(msg_at)}\n"
35
+ payload << "> #{msg_message}"
36
+ payload
37
+ end
38
+ end
data/lib/eye/process.rb CHANGED
@@ -19,7 +19,7 @@ class Eye::Process
19
19
 
20
20
  attr_accessor :pid, :parent_pid,
21
21
  :watchers, :config, :states_history,
22
- :children, :triggers, :name, :state_reason, :flapping_times
22
+ :children, :triggers, :name, :state_reason
23
23
 
24
24
  def initialize(config)
25
25
  raise 'you must supply a pid_file location' unless config[:pid_file]
@@ -31,8 +31,6 @@ class Eye::Process
31
31
  @triggers = []
32
32
  @name = @config[:name]
33
33
 
34
- @flapping_times = 0
35
-
36
34
  @states_history = Eye::Process::StatesHistory.new(100)
37
35
  @states_history << :unmonitored
38
36
 
@@ -78,4 +78,15 @@ module Eye::Process::Config
78
78
  !!self[:daemonize]
79
79
  end
80
80
 
81
+ def skip_group_action?(action)
82
+ if sga = self[:skip_group_actions]
83
+ res = sga[action]
84
+ if res == true
85
+ res
86
+ elsif res.is_a?(Array)
87
+ res.include?(self.state_name)
88
+ end
89
+ end
90
+ end
91
+
81
92
  end
@@ -76,4 +76,8 @@ module Eye::Process::Controller
76
76
  end
77
77
  end
78
78
 
79
+ def freeze
80
+ scheduler_freeze
81
+ end
82
+
79
83
  end
@@ -40,7 +40,7 @@ module Eye::Process::Data
40
40
 
41
41
  if @states_history
42
42
  h.merge!( state_changed_at: @states_history.last_state_changed_at.to_i,
43
- state_reason: @states_history.last_reason )
43
+ state_reason: @states_history.last_reason.to_s )
44
44
  end
45
45
 
46
46
  h.merge!(debug: debug_data) if debug
@@ -3,6 +3,11 @@ module Eye::Process::Scheduler
3
3
  # ex: schedule :update_config, config, "reason: update_config"
4
4
  def schedule(command, *args, &block)
5
5
  if scheduler.alive?
6
+ if scheduler_freeze?
7
+ warn ":#{command} ignoring to schedule, because scheduler is freeze"
8
+ return
9
+ end
10
+
6
11
  unless self.respond_to?(command, true)
7
12
  warn ":#{command} scheduling is unsupported"
8
13
  return
@@ -69,6 +74,18 @@ module Eye::Process::Scheduler
69
74
  @schedule_history ||= Eye::Process::StatesHistory.new(50)
70
75
  end
71
76
 
77
+ def scheduler_freeze
78
+ @scheduler_freeze = true
79
+ end
80
+
81
+ def scheduler_unfreeze
82
+ @scheduler_freeze = nil
83
+ end
84
+
85
+ def scheduler_freeze?
86
+ @scheduler_freeze
87
+ end
88
+
72
89
  private
73
90
 
74
91
  def remove_scheduler
@@ -1,5 +1,4 @@
1
1
  class Eye::Process::StatesHistory < Eye::Utils::Tail
2
-
3
2
  def push(state, reason = nil, tm = Time.now)
4
3
  super(state: state, at: tm.to_i, reason: reason)
5
4
  end
@@ -26,41 +25,4 @@ class Eye::Process::StatesHistory < Eye::Utils::Tail
26
25
  def last_state_changed_at
27
26
  Time.at(last[:at])
28
27
  end
29
-
30
- def seq?(*seq)
31
- str = states * ','
32
- substr = seq.flatten * ','
33
- str.include?(substr)
34
- end
35
-
36
- def end?(*seq)
37
- str = states * ','
38
- substr = seq.flatten * ','
39
- str.end_with?(substr)
40
- end
41
-
42
- def any?(*seq)
43
- states.any? do |st|
44
- seq.flatten.include?(st)
45
- end
46
- end
47
-
48
- def noone?(*seq)
49
- !states.all? do |st|
50
- seq.flatten.include?(st)
51
- end
52
- end
53
-
54
- def all?(*seq)
55
- states.all? do |st|
56
- seq.flatten.include?(st)
57
- end
58
- end
59
-
60
- def state_count(state)
61
- states.count do |st|
62
- st == state
63
- end
64
- end
65
-
66
- end
28
+ end
@@ -16,12 +16,20 @@ module Eye::Process::Trigger
16
16
  self.triggers.each { |trigger| trigger.notify(transition, state_reason) }
17
17
  end
18
18
 
19
- def retry_start_after_flapping
20
- return unless unmonitored?
21
- return unless state_reason.to_s.include?('flapping') # TODO: remove hackety
19
+ # conditional start, used in triggers, to start only from unmonitored state, and only if special reason
20
+ def conditional_start
21
+ unless unmonitored?
22
+ warn "skip, because in state #{state_name}"
23
+ return
24
+ end
25
+
26
+ previous_reason = state_reason
27
+ if last_scheduled_reason && previous_reason && last_scheduled_reason.class != previous_reason.class
28
+ warn "skip, last_scheduled_reason(#{last_scheduled_reason.inspect}) != previous_reason(#{previous_reason})"
29
+ return
30
+ end
22
31
 
23
- schedule :start, Eye::Reason.new(:'retry start after flapping')
24
- self.flapping_times += 1
32
+ start
25
33
  end
26
34
 
27
35
  private
data/lib/eye/reason.rb CHANGED
@@ -17,4 +17,7 @@ class Eye::Reason
17
17
  "#{super} by user"
18
18
  end
19
19
  end
20
+
21
+ class Flapping < Eye::Reason; end
22
+ class StartingGuard < Eye::Reason; end
20
23
  end
@@ -6,7 +6,9 @@ class Eye::SystemResources
6
6
  class << self
7
7
 
8
8
  def memory(pid)
9
- cache.proc_mem(pid).try(:resident)
9
+ if mem = cache.proc_mem(pid)
10
+ mem.resident
11
+ end
10
12
  end
11
13
 
12
14
  def cpu(pid)
@@ -49,7 +51,7 @@ class Eye::SystemResources
49
51
  end
50
52
 
51
53
  def cache
52
- @cache ||= Cache.new
54
+ Celluloid::Actor[:system_resources_cache]
53
55
  end
54
56
  end
55
57
 
@@ -96,4 +98,6 @@ class Eye::SystemResources
96
98
  end
97
99
  end
98
100
 
101
+ # Setup global sigar singleton here
102
+ Cache.supervise_as(:system_resources_cache)
99
103
  end
data/lib/eye/trigger.rb CHANGED
@@ -6,9 +6,10 @@ class Eye::Trigger
6
6
  autoload :StopChildren, 'eye/trigger/stop_children'
7
7
  autoload :WaitDependency, 'eye/trigger/wait_dependency'
8
8
  autoload :CheckDependency, 'eye/trigger/check_dependency'
9
+ autoload :StartingGuard, 'eye/trigger/starting_guard'
9
10
 
10
11
  TYPES = {:flapping => 'Flapping', :transition => 'Transition', :stop_children => 'StopChildren',
11
- :wait_dependency => 'WaitDependency', :check_dependency => 'CheckDependency'
12
+ :wait_dependency => 'WaitDependency', :check_dependency => 'CheckDependency', :starting_guard => 'StartingGuard'
12
13
  }
13
14
 
14
15
  attr_reader :message, :options, :process
@@ -99,6 +100,17 @@ class Eye::Trigger
99
100
  process.instance_exec(&p) if process.alive?
100
101
  end
101
102
 
103
+ def exec_proc(name = :do)
104
+ act = @options[name]
105
+ if act
106
+ res = instance_exec(&@options[name]) if act.is_a?(Proc)
107
+ res = send(act, process) if act.is_a?(Symbol)
108
+ res
109
+ else
110
+ true
111
+ end
112
+ end
113
+
102
114
  def defer(&block)
103
115
  Celluloid::Future.new(&block).value
104
116
  end
@@ -10,7 +10,7 @@ private
10
10
  def check_dependency(to)
11
11
  processes = names.map do |name|
12
12
  Eye::Control.find_nearest_process(name, process.group_name_pure, process.app_name)
13
- end.compact
13
+ end.compact.select { |p| p.state_name != :unmonitored }
14
14
  return if processes.empty?
15
15
  processes = Eye::Utils::AliveArray.new(processes)
16
16
 
@@ -8,6 +8,11 @@ class Eye::Trigger::Flapping < Eye::Trigger
8
8
  param :retry_in, [Float, Fixnum]
9
9
  param :retry_times, [Fixnum]
10
10
 
11
+ def initialize(*args)
12
+ super
13
+ @flapping_times = 0
14
+ end
15
+
11
16
  def check(transition)
12
17
  on_flapping if transition.event == :crashed && !good?
13
18
  end
@@ -30,12 +35,13 @@ private
30
35
  debug { 'flapping recognized!!!' }
31
36
 
32
37
  process.notify :error, 'flapping!'
33
- process.schedule :unmonitor, Eye::Reason.new(:flapping)
38
+ process.schedule :unmonitor, Eye::Reason::Flapping.new(:flapping)
34
39
 
35
40
  return unless retry_in
36
- return if retry_times && process.flapping_times >= retry_times
41
+ return if retry_times && @flapping_times >= retry_times
37
42
 
38
- process.schedule_in(retry_in.to_f, :retry_start_after_flapping)
43
+ @flapping_times += 1
44
+ process.schedule_in(retry_in.to_f, :conditional_start, Eye::Reason::Flapping.new('retry start after flapping'))
39
45
  end
40
46
 
41
47
  end
@@ -0,0 +1,64 @@
1
+ class Eye::Trigger::StartingGuard < Eye::Trigger
2
+
3
+ # check that process ready to start or not
4
+ # by custom user condition
5
+ # if not, process switched to :unmonitored, and then retry to start after :every interval
6
+ #
7
+ # trigger :starting_guard, every: 10.seconds, should: ->{ `cat /tmp/bla` == "bla" }
8
+
9
+ param :every, [Float, Fixnum], false, 10
10
+ param :times, [Fixnum]
11
+ param :retry_in, [Float, Fixnum]
12
+ param :retry_times, [Fixnum]
13
+ param :should, [Proc, Symbol]
14
+
15
+ def initialize(*args)
16
+ super
17
+
18
+ @retry_count = 0
19
+ @reretry_count = 0
20
+ end
21
+
22
+ def check(transition)
23
+ check_start if transition.to_name == :starting
24
+ end
25
+
26
+ def check_start
27
+ @retry_count += 1
28
+ condition = defer { exec_proc(:should) }
29
+
30
+ if condition
31
+ info "ok, process ready to start #{condition.inspect}"
32
+ @retry_count = 0
33
+ @reretry_count = 0
34
+ return
35
+ else
36
+ info "false executed condition"
37
+ end
38
+
39
+ new_time = nil
40
+ if every
41
+ if times
42
+ if (@retry_count < times)
43
+ new_time = Time.now + every
44
+ process.schedule_in every, :conditional_start, Eye::Reason::StartingGuard.new("starting_guard, retry start")
45
+ else
46
+ @retry_count = 0
47
+ @reretry_count += 1
48
+ if retry_in && (!retry_times || (@reretry_count < retry_times))
49
+ new_time = Time.now + retry_in
50
+ process.schedule_in retry_in, :conditional_start, Eye::Reason::StartingGuard.new("starting_guard, reretry start")
51
+ end
52
+ end
53
+ else
54
+ new_time = Time.now + every
55
+ process.schedule_in every, :conditional_start, Eye::Reason::StartingGuard.new("starting_guard, retry start")
56
+ end
57
+ end
58
+
59
+ retry_msg = new_time ? ", retry at '#{Eye::Utils.human_time2(new_time.to_i)}'" : ''
60
+ process.switch :unmonitoring, Eye::Reason::StartingGuard.new("starting_guard, failed condition#{retry_msg}")
61
+
62
+ raise Eye::Process::StateError.new("starting_guard, refused to start")
63
+ end
64
+ end
@@ -5,11 +5,7 @@ class Eye::Trigger::Transition < Eye::Trigger
5
5
  param :do, [Proc, Symbol]
6
6
 
7
7
  def check(trans)
8
- act = @options[:do]
9
- if act
10
- instance_exec(&@options[:do]) if act.is_a?(Proc)
11
- send(act, process) if act.is_a?(Symbol)
12
- end
8
+ exec_proc :do
13
9
  end
14
10
 
15
11
  end
data/lib/eye/utils.rb CHANGED
@@ -42,4 +42,17 @@ module Eye::Utils
42
42
  Time.at(unix_time.to_i).strftime(DF)
43
43
  end
44
44
 
45
+ def self.load_env(filename)
46
+ content = File.read(filename)
47
+ env_vars = content.split("\n")
48
+ h = {}
49
+ env_vars.each do |e|
50
+ e = e.gsub(/#.+$/, '').strip
51
+ next unless e.include?('=')
52
+ k, v = e.split('=', 2)
53
+ h[k] = v
54
+ end
55
+ h
56
+ end
57
+
45
58
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eye
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.7.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Makarchev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-19 00:00:00.000000000 Z
11
+ date: 2015-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.15.0
19
+ version: 0.16.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.15.0
26
+ version: 0.16.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: celluloid-io
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.15.0
33
+ version: 0.16.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.15.0
40
+ version: 0.16.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: state_machine
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +220,20 @@ dependencies:
220
220
  - - ">="
221
221
  - !ruby/object:Gem::Version
222
222
  version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: slack-notifier
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
223
237
  - !ruby/object:Gem::Dependency
224
238
  name: coveralls
225
239
  requirement: !ruby/object:Gem::Requirement
@@ -248,6 +262,34 @@ dependencies:
248
262
  - - ">="
249
263
  - !ruby/object:Gem::Version
250
264
  version: 0.8.1
265
+ - !ruby/object:Gem::Dependency
266
+ name: parallel_tests
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - "<="
270
+ - !ruby/object:Gem::Version
271
+ version: 1.3.1
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - "<="
277
+ - !ruby/object:Gem::Version
278
+ version: 1.3.1
279
+ - !ruby/object:Gem::Dependency
280
+ name: parallel_split_test
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '0'
251
293
  description: Process monitoring tool. Inspired from Bluepill and God. Requires Ruby(MRI)
252
294
  >= 1.9.3-p194. Uses Celluloid and Celluloid::IO.
253
295
  email: eye-rb@googlegroups.com
@@ -339,6 +381,7 @@ files:
339
381
  - lib/eye/notify.rb
340
382
  - lib/eye/notify/jabber.rb
341
383
  - lib/eye/notify/mail.rb
384
+ - lib/eye/notify/slack.rb
342
385
  - lib/eye/process.rb
343
386
  - lib/eye/process/children.rb
344
387
  - lib/eye/process/commands.rb
@@ -362,6 +405,7 @@ files:
362
405
  - lib/eye/trigger.rb
363
406
  - lib/eye/trigger/check_dependency.rb
364
407
  - lib/eye/trigger/flapping.rb
408
+ - lib/eye/trigger/starting_guard.rb
365
409
  - lib/eye/trigger/stop_children.rb
366
410
  - lib/eye/trigger/transition.rb
367
411
  - lib/eye/trigger/wait_dependency.rb
@@ -393,7 +437,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
393
437
  version: 1.3.6
394
438
  requirements: []
395
439
  rubyforge_project:
396
- rubygems_version: 2.2.2
440
+ rubygems_version: 2.4.5
397
441
  signing_key:
398
442
  specification_version: 4
399
443
  summary: Process monitoring tool. Inspired from Bluepill and God. Requires Ruby(MRI)