eye 0.2.1 → 0.2.2

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -17
  3. data/bin/eye +5 -0
  4. data/examples/notify.eye +18 -0
  5. data/examples/process_thin.rb +29 -0
  6. data/examples/sidekiq.eye +5 -1
  7. data/examples/test.eye +24 -17
  8. data/examples/thin-farm.eye +29 -0
  9. data/examples/unicorn.eye +2 -0
  10. data/eye.gemspec +1 -1
  11. data/lib/eye.rb +1 -1
  12. data/lib/eye/checker.rb +3 -5
  13. data/lib/eye/checker/http.rb +1 -2
  14. data/lib/eye/checker/socket.rb +2 -2
  15. data/lib/eye/controller/commands.rb +2 -0
  16. data/lib/eye/controller/send_command.rb +8 -2
  17. data/lib/eye/dsl.rb +1 -0
  18. data/lib/eye/dsl/opts.rb +36 -2
  19. data/lib/eye/dsl/pure_opts.rb +17 -39
  20. data/lib/eye/{checker → dsl}/validation.rb +15 -5
  21. data/lib/eye/group.rb +13 -4
  22. data/lib/eye/group/chain.rb +11 -0
  23. data/lib/eye/notify.rb +1 -1
  24. data/lib/eye/notify/mail.rb +1 -1
  25. data/lib/eye/process/child.rb +0 -2
  26. data/lib/eye/process/commands.rb +11 -14
  27. data/lib/eye/process/monitor.rb +10 -16
  28. data/lib/eye/process/scheduler.rb +8 -3
  29. data/lib/eye/process/states.rb +1 -2
  30. data/lib/eye/process/system.rb +38 -7
  31. data/lib/eye/process/watchers.rb +3 -3
  32. data/lib/eye/settings.rb +1 -1
  33. data/lib/eye/system.rb +33 -16
  34. data/lib/eye/trigger.rb +1 -1
  35. data/lib/eye/utils/celluloid_chain.rb +2 -0
  36. data/spec/checker/cpu_spec.rb +1 -1
  37. data/spec/checker/http_spec.rb +2 -2
  38. data/spec/checker/memory_spec.rb +2 -2
  39. data/spec/checker_spec.rb +1 -1
  40. data/spec/controller/controller_spec.rb +6 -0
  41. data/spec/controller/find_objects_spec.rb +6 -0
  42. data/spec/controller/intergration_spec.rb +24 -0
  43. data/spec/dsl/checks_spec.rb +2 -2
  44. data/spec/dsl/notify_spec.rb +12 -3
  45. data/spec/dsl/with_server_spec.rb +26 -2
  46. data/spec/process/checks/child_checks_spec.rb +1 -1
  47. data/spec/process/checks/memory_spec.rb +14 -0
  48. data/spec/process/scheduler_spec.rb +8 -0
  49. data/spec/process/system_spec.rb +27 -4
  50. data/spec/spec_helper.rb +3 -1
  51. data/spec/system_spec.rb +12 -5
  52. data/spec/utils/celluloid_chain_spec.rb +8 -0
  53. metadata +8 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b1592106a2ce3c26da8ad55f6b0036b10e5932fc
4
- data.tar.gz: ff73a4ae40c4eeef57e9c50df0e50e8220eb187f
3
+ metadata.gz: ec5135b6c531e9451f98ec8b9d36a54d2e57e3f9
4
+ data.tar.gz: fd8011e705ee96d0d24dffbe03be598a18b285c4
5
5
  SHA512:
6
- metadata.gz: b81127c859a0e48c6a08b7109582cddcdb12731b93eca191ae3fe65289703075e32c53f3552db24fcca3d693e61ada93ca7bfcae1bed4488724c54918ed6c880
7
- data.tar.gz: 22e769a89a91343374045e502404f2fa26002f9a641807d4f772354774a3f88837cf486afb18da4880738548d9b8522f0c865e2b9c8ed2ae6cc9757d3da1ea78
6
+ metadata.gz: 59237be9adb524bdc90ddb9203d3246e7e6fc03f4b9c7398df2380fba2423e68592a996ac720ff04cd8a813b34ed8a27a1c259421907dd1103b18ad508c9decd
7
+ data.tar.gz: b741a332f8888e3f5a2dd50af91e0dbafebed8f8dcc406f9f8cab270b565f3ce2624adef2e4b9c2b3be0a01ff18dcbaf28159d4ba55b6d532e37711b8c9fa5cd
data/README.md CHANGED
@@ -14,26 +14,31 @@ Config example, shows some typical processes and most of the options (see in exa
14
14
 
15
15
  examples/test.eye
16
16
  ```ruby
17
- Eye.load("./eye/*.rb") # load submodules
17
+ # load submodules, here just for example
18
+ Eye.load("./eye/*.rb")
18
19
 
20
+ # Eye self-configuration section
19
21
  Eye.config do
20
- logger "/tmp/eye.log" # eye logger
21
- logger_level Logger::DEBUG
22
+ logger "/tmp/eye.log"
22
23
  end
23
24
 
25
+ # Adding application
24
26
  Eye.application "test" do
27
+ # All options inherits down to the config leafs.
28
+ # except `env`, which merging down
29
+
25
30
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
26
31
  stdall "trash.log" # stdout,err logs for processes by default
27
32
  env "APP_ENV" => "production" # global env for each processes
28
- triggers :flapping, :times => 10, :within => 1.minute
33
+ triggers :flapping, :times => 10, :within => 1.minute #
34
+ checks :cpu, :below => 100, :times => 3 # global check for all processes
29
35
 
30
36
  group "samples" do
31
- env "A" => "1" # merging to app env
32
- chain :grace => 5.seconds, :action => :restart # restarting with 5s interval, one by one.
37
+ chain :grace => 5.seconds # chained start-restart with 5s interval, one by one.
33
38
 
34
39
  # eye daemonized process
35
- process("sample1") do
36
- pid_file "1.pid" # will be expanded with working_dir
40
+ process :sample1 do
41
+ pid_file "1.pid" # pid_path will be expanded with the working_dir
37
42
  start_command "ruby ./sample.rb"
38
43
  daemonize true
39
44
  stdall "sample1.log"
@@ -42,7 +47,7 @@ Eye.application "test" do
42
47
  end
43
48
 
44
49
  # self daemonized process
45
- process("sample2") do
50
+ process :sample2 do
46
51
  pid_file "2.pid"
47
52
  start_command "ruby ./sample.rb -d --pid 2.pid --log sample2.log"
48
53
  stop_command "kill -9 {PID}"
@@ -52,7 +57,7 @@ Eye.application "test" do
52
57
  end
53
58
 
54
59
  # daemon with 3 childs
55
- process("forking") do
60
+ process :forking do
56
61
  pid_file "forking.pid"
57
62
  start_command "ruby ./forking.rb start"
58
63
  stop_command "ruby forking.rb stop"
@@ -67,17 +72,19 @@ Eye.application "test" do
67
72
  end
68
73
  end
69
74
 
75
+ # eventmachine process, daemonized with eye
70
76
  process :event_machine do |p|
71
- p.pid_file = 'em.pid'
72
- p.start_command = 'ruby em.rb'
73
- p.stdout = 'em.log'
74
- p.daemonize = true
75
- p.stop_signals = [:QUIT, 2.seconds, :KILL]
77
+ pid_file 'em.pid'
78
+ start_command 'ruby em.rb'
79
+ stdout 'em.log'
80
+ daemonize true
81
+ stop_signals [:QUIT, 2.seconds, :KILL]
76
82
 
77
- p.checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
78
- :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
83
+ checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
84
+ :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
79
85
  end
80
86
 
87
+ # thin process, self daemonized
81
88
  process :thin do
82
89
  pid_file "thin.pid"
83
90
  start_command "bundle exec thin start -R thin.ru -p 33233 -d -l thin.log -P thin.pid"
data/bin/eye CHANGED
@@ -78,6 +78,11 @@ class Cli < Thor
78
78
  send_command(:signal, sig, *targets)
79
79
  end
80
80
 
81
+ desc "break TARGET[,...]", "break group chain executing"
82
+ def break(*targets)
83
+ send_command(:break_chain, *targets)
84
+ end
85
+
81
86
  desc "trace [TARGET]", "tracing log for app,group or process"
82
87
  def trace(target = "")
83
88
  log_trace(target)
@@ -0,0 +1,18 @@
1
+ # Notify example
2
+
3
+ Eye.config do
4
+ mail :host => "mx.some.host", :port => 25, :domain => "some.host"
5
+ contact :errors, :mail, 'error@some.host'
6
+ contact :dev, :mail, 'dev@some.host'
7
+ end
8
+
9
+ Eye.application :some do
10
+ notify :errors
11
+
12
+ process :some_process do
13
+ notify :dev, :warn
14
+
15
+ ...
16
+ end
17
+
18
+ end
@@ -0,0 +1,29 @@
1
+
2
+ def thin(proxy, port)
3
+ name = "thin-#{port}"
4
+
5
+ opts = [
6
+ "-l thins.log",
7
+ "-p #{port}",
8
+ "-P #{name}.pid",
9
+ "-d",
10
+ "-R thin.ru",
11
+ "--tag #{proxy.app.name}.#{proxy.name}",
12
+ "-t 60",
13
+ "-e #{proxy.env["RAILS_ENV"]}",
14
+ "-c #{proxy.working_dir}",
15
+ "-a 127.0.0.1"
16
+ ]
17
+
18
+ proxy.process(name) do
19
+ pid_file "#{name}.pid"
20
+
21
+ start_command "#{BUNDLE} exec thin start #{opts * ' '}"
22
+ stop_signals [:QUIT, 2.seconds, :TERM, 1.seconds, :KILL]
23
+
24
+ stdall "thin.stdall.log"
25
+
26
+ checks :http, :url => "http://127.0.0.1:#{port}/hello", :pattern => /World/,
27
+ :every => 5.seconds, :times => [2, 3], :timeout => 1.second
28
+ end
29
+ end
@@ -1,6 +1,10 @@
1
+ # Example: how to run sidekiq daemon
2
+
1
3
  def sidekiq_process(proxy, name)
4
+ rails_env = proxy.env['RAILS_ENV']
5
+
2
6
  proxy.process(name) do
3
- start_command "ruby ./bin/sidekiq -e #{proxy.env['RAILS_ENV']} -C ./config/sidekiq.#{proxy.env['RAILS_ENV']}.yml"
7
+ start_command "ruby ./bin/sidekiq -e #{rails_env} -C ./config/sidekiq.#{rails_env}.yml"
4
8
  pid_file "tmp/pids/#{name}.pid"
5
9
  stdall "log/#{name}.log"
6
10
  daemonize true
@@ -1,23 +1,28 @@
1
- Eye.load("./eye/*.rb") # load submodules
1
+ # load submodules, here just for example
2
+ Eye.load("./eye/*.rb")
2
3
 
4
+ # Eye self-configuration section
3
5
  Eye.config do
4
- logger "/tmp/eye.log" # eye logger
5
- logger_level Logger::DEBUG
6
+ logger "/tmp/eye.log"
6
7
  end
7
8
 
9
+ # Adding application
8
10
  Eye.application "test" do
11
+ # All options inherits down to the config leafs.
12
+ # except `env`, which merging down
13
+
9
14
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
10
15
  stdall "trash.log" # stdout,err logs for processes by default
11
16
  env "APP_ENV" => "production" # global env for each processes
12
- triggers :flapping, :times => 10, :within => 1.minute
17
+ triggers :flapping, :times => 10, :within => 1.minute #
18
+ checks :cpu, :below => 100, :times => 3 # global check for all processes
13
19
 
14
20
  group "samples" do
15
- env "A" => "1" # merging to app env
16
- chain :grace => 5.seconds, :action => :restart # restarting with 5s interval, one by one.
21
+ chain :grace => 5.seconds # chained start-restart with 5s interval, one by one.
17
22
 
18
23
  # eye daemonized process
19
- process("sample1") do
20
- pid_file "1.pid" # will be expanded with working_dir
24
+ process :sample1 do
25
+ pid_file "1.pid" # pid_path will be expanded with the working_dir
21
26
  start_command "ruby ./sample.rb"
22
27
  daemonize true
23
28
  stdall "sample1.log"
@@ -26,7 +31,7 @@ Eye.application "test" do
26
31
  end
27
32
 
28
33
  # self daemonized process
29
- process("sample2") do
34
+ process :sample2 do
30
35
  pid_file "2.pid"
31
36
  start_command "ruby ./sample.rb -d --pid 2.pid --log sample2.log"
32
37
  stop_command "kill -9 {PID}"
@@ -36,7 +41,7 @@ Eye.application "test" do
36
41
  end
37
42
 
38
43
  # daemon with 3 childs
39
- process("forking") do
44
+ process :forking do
40
45
  pid_file "forking.pid"
41
46
  start_command "ruby ./forking.rb start"
42
47
  stop_command "ruby forking.rb stop"
@@ -51,17 +56,19 @@ Eye.application "test" do
51
56
  end
52
57
  end
53
58
 
59
+ # eventmachine process, daemonized with eye
54
60
  process :event_machine do |p|
55
- p.pid_file = 'em.pid'
56
- p.start_command = 'ruby em.rb'
57
- p.stdout = 'em.log'
58
- p.daemonize = true
59
- p.stop_signals = [:QUIT, 2.seconds, :KILL]
61
+ pid_file 'em.pid'
62
+ start_command 'ruby em.rb'
63
+ stdout 'em.log'
64
+ daemonize true
65
+ stop_signals [:QUIT, 2.seconds, :KILL]
60
66
 
61
- p.checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
62
- :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
67
+ checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
68
+ :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
63
69
  end
64
70
 
71
+ # thin process, self daemonized
65
72
  process :thin do
66
73
  pid_file "thin.pid"
67
74
  start_command "bundle exec thin start -R thin.ru -p 33233 -d -l thin.log -P thin.pid"
@@ -0,0 +1,29 @@
1
+ RUBY = 'ruby'
2
+ BUNDLE = 'bundle'
3
+
4
+ Eye.load("process_thin.rb")
5
+
6
+ Eye.config do
7
+ logger "/tmp/eye.log"
8
+ end
9
+
10
+ Eye.app 'thin-farm' do
11
+ working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
12
+ env "RAILS_ENV" => "production"
13
+
14
+ stop_on_delete true # this option means, when we change pids and load config,
15
+ # deleted processes will be stops
16
+
17
+ triggers :flapping, :times => 10, :within => 1.minute
18
+ checks :memory, :below => 60.megabytes, :every => 30.seconds, :times => 5
19
+
20
+ group :web do
21
+ chain :action => :restart, :grace => 5.seconds
22
+ chain :action => :start, :grace => 0.2.seconds
23
+
24
+ (5555..5560).each do |port|
25
+ thin self, port
26
+ end
27
+ end
28
+
29
+ end
@@ -1,3 +1,5 @@
1
+ # Example: now to run unicorn, and monitor its childs processes
2
+
1
3
  RUBY = '/usr/local/ruby/1.9.3/bin/ruby' # ruby on the server
2
4
  RAILS_ENV = 'production'
3
5
 
@@ -32,7 +32,7 @@ Gem::Specification.new do |gem|
32
32
  gem.add_development_dependency 'ruby-graphviz'
33
33
  gem.add_development_dependency 'forking'
34
34
  gem.add_development_dependency 'fakeweb'
35
- gem.add_development_dependency 'eventmachine'
35
+ gem.add_development_dependency 'eventmachine', ">= 1.0.3"
36
36
  gem.add_development_dependency 'sinatra'
37
37
  gem.add_development_dependency 'thin'
38
38
  gem.add_development_dependency 'xmpp4r'
data/lib/eye.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Eye
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  ABOUT = "Eye v#{VERSION} (c) 2012-2013 @kostya"
4
4
 
5
5
  autoload :Process, 'eye/process'
@@ -1,8 +1,6 @@
1
1
  class Eye::Checker
2
2
  include Eye::Logger::Helpers
3
3
 
4
- autoload :Validation, 'eye/checker/validation'
5
-
6
4
  autoload :Memory, 'eye/checker/memory'
7
5
  autoload :Cpu, 'eye/checker/cpu'
8
6
  autoload :Http, 'eye/checker/http'
@@ -51,7 +49,6 @@ class Eye::Checker
51
49
  end
52
50
 
53
51
  def check
54
- tm1 = Time.now
55
52
  @value = get_value
56
53
  @values << {:value => @value, :good => good?(value)}
57
54
 
@@ -62,7 +59,7 @@ class Eye::Checker
62
59
  result = false if bad_count >= min_tries
63
60
  end
64
61
 
65
- info "#{last_human_values} => #{result ? 'OK' : 'Fail'} (#{Time.now - tm1}s)"
62
+ info "#{last_human_values} => #{result ? 'OK' : 'Fail'}"
66
63
  result
67
64
  end
68
65
 
@@ -112,8 +109,9 @@ class Eye::Checker
112
109
  @values[-1][:value] if @values.present?
113
110
  end
114
111
 
115
- extend Eye::Checker::Validation
112
+ extend Eye::Dsl::Validation
116
113
  param :every, [Fixnum, Float], false, 5
117
114
  param :times, [Fixnum, Array]
115
+ param :fire, Symbol, nil, nil, [:stop, :restart, :unmonitor, :nothing]
118
116
 
119
117
  end
@@ -38,8 +38,7 @@ class Eye::Checker::Http < Eye::Checker
38
38
  end
39
39
 
40
40
  def get_value_sync
41
- _session = session
42
- res = _session.start{ |http| http.get(@uri.path) }
41
+ res = session.start{ |http| http.get(@uri.request_uri) }
43
42
  {:result => res}
44
43
 
45
44
  rescue Timeout::Error => ex
@@ -5,7 +5,7 @@ class Eye::Checker::Socket < Eye::Checker
5
5
  #
6
6
  # Available parameters:
7
7
  # :addr the socket addr to open. The format is tcp://<host>:<port> or unix:<path>
8
- # :timeout generic timeout for opening the socket or reading data
8
+ # :timeout generic timeout for reading data from socket
9
9
  # :open_timeout override generic timeout for the connection
10
10
  # :read_timeout override generic timeout for data read/write
11
11
  # :send_data after connection send this data
@@ -18,7 +18,7 @@ class Eye::Checker::Socket < Eye::Checker
18
18
  param :read_timeout, [Fixnum, Float]
19
19
  param :send_data
20
20
  param :expect_data, [String, Regexp, Proc]
21
- param :protocol, [Symbol]
21
+ param :protocol, [Symbol], nil, nil, [:default, :em_object]
22
22
 
23
23
  def check_name
24
24
  'socket'
@@ -14,6 +14,8 @@ module Eye::Controller::Commands
14
14
  exclusive{ send_command(cmd, *args) }
15
15
  when :signal
16
16
  signal(*args)
17
+ when :break_chain
18
+ break_chain(*args)
17
19
  when :load
18
20
  exclusive{ load(*args) }
19
21
  when :info
@@ -21,6 +21,12 @@ module Eye::Controller::SendCommand
21
21
  end
22
22
  end
23
23
 
24
+ def break_chain(*obj_strs)
25
+ matched_objects(*obj_strs) do |obj|
26
+ obj.send_command(:break_chain)
27
+ end
28
+ end
29
+
24
30
  private
25
31
 
26
32
  def matched_objects(*obj_strs, &block)
@@ -60,7 +66,7 @@ private
60
66
  # nil if not found
61
67
  def find_objects(*obj_strs)
62
68
  return [] if obj_strs.blank?
63
- return @applications if obj_strs.size == 1 && obj_strs[0].strip == 'all'
69
+ return @applications.dup if obj_strs.size == 1 && (obj_strs[0].strip == 'all' || obj_strs[0].strip == '*')
64
70
 
65
71
  res = obj_strs.map{|c| c.split(",").map{|mask| find_objects_by_mask(mask) }}.flatten
66
72
 
@@ -76,7 +82,7 @@ private
76
82
  res = final
77
83
  end
78
84
 
79
- res.present? ? Eye::Utils::AliveArray.new(res) : res
85
+ res.present? ? Eye::Utils::AliveArray.new(res) : []
80
86
  end
81
87
 
82
88
  def find_objects_by_mask(mask)
@@ -14,6 +14,7 @@ class Eye::Dsl
14
14
  autoload :Validate, 'eye/dsl/validate'
15
15
  autoload :Chain, 'eye/dsl/chain'
16
16
  autoload :ConfigOpts, 'eye/dsl/config_opts'
17
+ autoload :Validation, 'eye/dsl/validation'
17
18
 
18
19
  class Error < Exception; end
19
20
  extend Eye::Dsl::Validate
@@ -97,8 +97,42 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
97
97
  h.instance_eval(&block)
98
98
  groups = h.config.delete :groups
99
99
  processes = h.config.delete :processes
100
- self.config[:groups].merge!(groups) if groups.present?
101
- self.config[:processes].merge!(processes) if processes.present?
100
+
101
+ if groups.present?
102
+ config[:groups] ||= {}
103
+ config[:groups].merge!(groups)
104
+ end
105
+
106
+ if processes.present?
107
+ config[:processes] ||= {}
108
+ config[:processes].merge!(processes)
109
+ end
110
+ end
111
+
112
+ # execute part of config on particular server
113
+ # array of strings
114
+ # regexp
115
+ # string
116
+ def with_server(glob = nil, &block)
117
+ on_server = true
118
+
119
+ if glob.present?
120
+ host = Eye::System.host
121
+
122
+ if glob.is_a?(Array)
123
+ on_server = !!glob.any?{|elem| elem == host}
124
+ elsif glob.is_a?(Regexp)
125
+ on_server = !!host.match(glob)
126
+ elsif glob.is_a?(String) || glob.is_a?(Symbol)
127
+ on_server = (host == glob.to_s)
128
+ end
129
+ end
130
+
131
+ scoped do
132
+ with_condition(on_server, &block)
133
+ end
134
+
135
+ on_server
102
136
  end
103
137
 
104
138
  end