eye 0.6.4 → 0.7.pre

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.
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)