eye 0.1.11

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 (190) hide show
  1. data/.gitignore +31 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +132 -0
  6. data/Rakefile +18 -0
  7. data/bin/eye +282 -0
  8. data/bin/loader_eye +56 -0
  9. data/examples/processes/em.rb +56 -0
  10. data/examples/processes/forking.rb +20 -0
  11. data/examples/processes/sample.rb +144 -0
  12. data/examples/rbenv.eye +11 -0
  13. data/examples/test.eye +65 -0
  14. data/examples/unicorn.eye +29 -0
  15. data/eye.gemspec +37 -0
  16. data/lib/eye.rb +25 -0
  17. data/lib/eye/application.rb +65 -0
  18. data/lib/eye/checker.rb +118 -0
  19. data/lib/eye/checker/cpu.rb +27 -0
  20. data/lib/eye/checker/file_ctime.rb +29 -0
  21. data/lib/eye/checker/file_size.rb +38 -0
  22. data/lib/eye/checker/http.rb +94 -0
  23. data/lib/eye/checker/memory.rb +27 -0
  24. data/lib/eye/checker/socket.rb +148 -0
  25. data/lib/eye/checker/validation.rb +49 -0
  26. data/lib/eye/child_process.rb +75 -0
  27. data/lib/eye/client.rb +32 -0
  28. data/lib/eye/control.rb +2 -0
  29. data/lib/eye/controller.rb +43 -0
  30. data/lib/eye/controller/commands.rb +64 -0
  31. data/lib/eye/controller/helpers.rb +61 -0
  32. data/lib/eye/controller/load.rb +224 -0
  33. data/lib/eye/controller/send_command.rb +88 -0
  34. data/lib/eye/controller/status.rb +136 -0
  35. data/lib/eye/dsl.rb +52 -0
  36. data/lib/eye/dsl/application_opts.rb +33 -0
  37. data/lib/eye/dsl/chain.rb +12 -0
  38. data/lib/eye/dsl/child_process_opts.rb +7 -0
  39. data/lib/eye/dsl/config_opts.rb +11 -0
  40. data/lib/eye/dsl/group_opts.rb +27 -0
  41. data/lib/eye/dsl/helpers.rb +12 -0
  42. data/lib/eye/dsl/main.rb +58 -0
  43. data/lib/eye/dsl/opts.rb +88 -0
  44. data/lib/eye/dsl/process_opts.rb +21 -0
  45. data/lib/eye/dsl/pure_opts.rb +132 -0
  46. data/lib/eye/dsl/validate.rb +41 -0
  47. data/lib/eye/group.rb +125 -0
  48. data/lib/eye/group/chain.rb +68 -0
  49. data/lib/eye/io/unix_server.rb +44 -0
  50. data/lib/eye/io/unix_socket.rb +39 -0
  51. data/lib/eye/loader.rb +13 -0
  52. data/lib/eye/logger.rb +80 -0
  53. data/lib/eye/process.rb +83 -0
  54. data/lib/eye/process/child.rb +61 -0
  55. data/lib/eye/process/commands.rb +256 -0
  56. data/lib/eye/process/config.rb +70 -0
  57. data/lib/eye/process/controller.rb +72 -0
  58. data/lib/eye/process/data.rb +46 -0
  59. data/lib/eye/process/monitor.rb +97 -0
  60. data/lib/eye/process/notify.rb +17 -0
  61. data/lib/eye/process/scheduler.rb +50 -0
  62. data/lib/eye/process/states.rb +92 -0
  63. data/lib/eye/process/states_history.rb +62 -0
  64. data/lib/eye/process/system.rb +60 -0
  65. data/lib/eye/process/trigger.rb +32 -0
  66. data/lib/eye/process/watchers.rb +67 -0
  67. data/lib/eye/server.rb +51 -0
  68. data/lib/eye/settings.rb +35 -0
  69. data/lib/eye/system.rb +145 -0
  70. data/lib/eye/system_resources.rb +83 -0
  71. data/lib/eye/trigger.rb +53 -0
  72. data/lib/eye/trigger/flapping.rb +24 -0
  73. data/lib/eye/utils.rb +5 -0
  74. data/lib/eye/utils/alive_array.rb +31 -0
  75. data/lib/eye/utils/celluloid_chain.rb +51 -0
  76. data/lib/eye/utils/leak_19.rb +7 -0
  77. data/lib/eye/utils/tail.rb +20 -0
  78. data/spec/checker/cpu_spec.rb +58 -0
  79. data/spec/checker/file_ctime_spec.rb +34 -0
  80. data/spec/checker/file_size_spec.rb +107 -0
  81. data/spec/checker/http_spec.rb +109 -0
  82. data/spec/checker/memory_spec.rb +64 -0
  83. data/spec/checker/socket_spec.rb +116 -0
  84. data/spec/checker_spec.rb +188 -0
  85. data/spec/child_process/child_process_spec.rb +46 -0
  86. data/spec/client_server_spec.rb +34 -0
  87. data/spec/controller/commands_spec.rb +92 -0
  88. data/spec/controller/controller_spec.rb +133 -0
  89. data/spec/controller/find_objects_spec.rb +150 -0
  90. data/spec/controller/group_spec.rb +110 -0
  91. data/spec/controller/intergration_spec.rb +327 -0
  92. data/spec/controller/load_spec.rb +326 -0
  93. data/spec/controller/races_spec.rb +70 -0
  94. data/spec/controller/stop_on_delete_spec.rb +157 -0
  95. data/spec/dsl/chain_spec.rb +140 -0
  96. data/spec/dsl/checks_spec.rb +202 -0
  97. data/spec/dsl/config_spec.rb +44 -0
  98. data/spec/dsl/dsl_spec.rb +73 -0
  99. data/spec/dsl/getter_spec.rb +223 -0
  100. data/spec/dsl/integration_spec.rb +311 -0
  101. data/spec/dsl/load_spec.rb +52 -0
  102. data/spec/dsl/process_spec.rb +330 -0
  103. data/spec/dsl/sub_procs_spec.rb +93 -0
  104. data/spec/dsl/with_server_spec.rb +104 -0
  105. data/spec/example/em.rb +57 -0
  106. data/spec/example/forking.rb +20 -0
  107. data/spec/example/sample.rb +154 -0
  108. data/spec/fixtures/dsl/0.rb +8 -0
  109. data/spec/fixtures/dsl/0a.rb +8 -0
  110. data/spec/fixtures/dsl/0c.rb +8 -0
  111. data/spec/fixtures/dsl/1.rb +5 -0
  112. data/spec/fixtures/dsl/bad.eye +6 -0
  113. data/spec/fixtures/dsl/configs/1.eye +3 -0
  114. data/spec/fixtures/dsl/configs/2.eye +1 -0
  115. data/spec/fixtures/dsl/configs/3.eye +1 -0
  116. data/spec/fixtures/dsl/configs/4.eye +3 -0
  117. data/spec/fixtures/dsl/empty.eye +20 -0
  118. data/spec/fixtures/dsl/include_test.eye +5 -0
  119. data/spec/fixtures/dsl/include_test/1.rb +6 -0
  120. data/spec/fixtures/dsl/include_test/ha.rb +4 -0
  121. data/spec/fixtures/dsl/include_test2.eye +5 -0
  122. data/spec/fixtures/dsl/integration.eye +30 -0
  123. data/spec/fixtures/dsl/integration2.eye +32 -0
  124. data/spec/fixtures/dsl/integration_locks.eye +30 -0
  125. data/spec/fixtures/dsl/integration_sor.eye +32 -0
  126. data/spec/fixtures/dsl/integration_sor2.eye +27 -0
  127. data/spec/fixtures/dsl/integration_sor3.eye +32 -0
  128. data/spec/fixtures/dsl/load.eye +25 -0
  129. data/spec/fixtures/dsl/load2.eye +7 -0
  130. data/spec/fixtures/dsl/load2_dup2.eye +13 -0
  131. data/spec/fixtures/dsl/load2_dup_pid.eye +7 -0
  132. data/spec/fixtures/dsl/load3.eye +10 -0
  133. data/spec/fixtures/dsl/load4.eye +7 -0
  134. data/spec/fixtures/dsl/load5.eye +8 -0
  135. data/spec/fixtures/dsl/load6.eye +17 -0
  136. data/spec/fixtures/dsl/load_dubls.eye +36 -0
  137. data/spec/fixtures/dsl/load_dup_ex_names.eye +15 -0
  138. data/spec/fixtures/dsl/load_error.eye +5 -0
  139. data/spec/fixtures/dsl/load_error_folder/load3.eye +10 -0
  140. data/spec/fixtures/dsl/load_error_folder/load4.eye +7 -0
  141. data/spec/fixtures/dsl/load_folder/load3.eye +10 -0
  142. data/spec/fixtures/dsl/load_folder/load4.eye +7 -0
  143. data/spec/fixtures/dsl/load_int.eye +8 -0
  144. data/spec/fixtures/dsl/load_int2.eye +13 -0
  145. data/spec/fixtures/dsl/load_logger.eye +26 -0
  146. data/spec/fixtures/dsl/load_logger2.eye +3 -0
  147. data/spec/fixtures/dsl/long_load.eye +5 -0
  148. data/spec/fixtures/dsl/subfolder1/proc1.rb +3 -0
  149. data/spec/fixtures/dsl/subfolder2.eye +9 -0
  150. data/spec/fixtures/dsl/subfolder2/common.rb +1 -0
  151. data/spec/fixtures/dsl/subfolder2/proc2.rb +3 -0
  152. data/spec/fixtures/dsl/subfolder2/sub/proc3.rb +6 -0
  153. data/spec/fixtures/dsl/subfolder3.eye +8 -0
  154. data/spec/fixtures/dsl/subfolder3/common.rb +1 -0
  155. data/spec/fixtures/dsl/subfolder3/proc4.rb +3 -0
  156. data/spec/fixtures/dsl/subfolder3/sub/proc5.rb +6 -0
  157. data/spec/fixtures/dsl/subfolder4.eye +6 -0
  158. data/spec/fixtures/dsl/subfolder4/a.rb +2 -0
  159. data/spec/fixtures/dsl/subfolder4/b.rb +1 -0
  160. data/spec/fixtures/dsl/subfolder4/c.rb +1 -0
  161. data/spec/mock_spec.rb +32 -0
  162. data/spec/process/checks/child_checks_spec.rb +79 -0
  163. data/spec/process/checks/cpu_spec.rb +114 -0
  164. data/spec/process/checks/ctime_spec.rb +43 -0
  165. data/spec/process/checks/fsize_spec.rb +22 -0
  166. data/spec/process/checks/http_spec.rb +52 -0
  167. data/spec/process/checks/intergration_spec.rb +32 -0
  168. data/spec/process/checks/memory_spec.rb +113 -0
  169. data/spec/process/child_process_spec.rb +125 -0
  170. data/spec/process/config_spec.rb +75 -0
  171. data/spec/process/controller_spec.rb +173 -0
  172. data/spec/process/monitoring_spec.rb +180 -0
  173. data/spec/process/restart_spec.rb +174 -0
  174. data/spec/process/scheduler_spec.rb +150 -0
  175. data/spec/process/start_spec.rb +261 -0
  176. data/spec/process/states_history_spec.rb +118 -0
  177. data/spec/process/stop_spec.rb +150 -0
  178. data/spec/process/system_spec.rb +100 -0
  179. data/spec/process/triggers/flapping_spec.rb +81 -0
  180. data/spec/process/update_config_spec.rb +63 -0
  181. data/spec/spec_helper.rb +120 -0
  182. data/spec/support/rr_celluloid.rb +36 -0
  183. data/spec/support/scheduler_hack.rb +16 -0
  184. data/spec/support/spec_support.rb +164 -0
  185. data/spec/system_resources_spec.rb +59 -0
  186. data/spec/system_spec.rb +170 -0
  187. data/spec/utils/alive_array_spec.rb +50 -0
  188. data/spec/utils/celluloid_chain_spec.rb +82 -0
  189. data/spec/utils/tail_spec.rb +21 -0
  190. metadata +558 -0
@@ -0,0 +1,44 @@
1
+ require 'socket'
2
+
3
+ module Celluloid
4
+ module IO
5
+ # UNIXServer with combined blocking and evented support
6
+ class UNIXServer
7
+ extend Forwardable
8
+ def_delegators :@server, :listen, :sysaccept, :close, :closed?
9
+
10
+ def self.open(socket_path)
11
+ self.new(socket_path)
12
+ end
13
+
14
+ def initialize(socket_path)
15
+ @server = ::UNIXServer.new(socket_path)
16
+ end
17
+
18
+ def accept
19
+ actor = Thread.current[:actor]
20
+
21
+ if evented?
22
+ Celluloid.current_actor.wait_readable @server
23
+ accept_nonblock
24
+ else
25
+ Celluloid::IO::UNIXSocket.from_ruby_socket @server.accept
26
+ end
27
+ end
28
+
29
+ def accept_nonblock
30
+ Celluloid::IO::UNIXSocket.from_ruby_socket @server.accept_nonblock
31
+ end
32
+
33
+ def to_io
34
+ @server
35
+ end
36
+
37
+ # Are we inside a Celluloid ::IO actor?
38
+ def evented?
39
+ actor = Thread.current[:actor]
40
+ actor && actor.mailbox.is_a?(Celluloid::IO::Mailbox)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,39 @@
1
+ require 'socket'
2
+
3
+ module Celluloid
4
+ module IO
5
+ # UNIXSocket with combined blocking and evented support
6
+ class UNIXSocket
7
+ include CommonMethods
8
+ extend Forwardable
9
+
10
+ def_delegators :@socket, :read_nonblock, :write_nonblock, :close, :closed?, :readline, :puts, :addr
11
+
12
+ # Convert a Ruby UNIXSocket into a Celluloid::IO::UNIXSocket
13
+ def self.from_ruby_socket(ruby_socket)
14
+ # Some hax here, but whatever ;)
15
+ socket = allocate
16
+ socket.instance_variable_set(:@socket, ruby_socket)
17
+ socket
18
+ end
19
+
20
+ # Open a UNIX connection.
21
+ def self.open(socket_path, &block)
22
+ self.new(socket_path, &block)
23
+ end
24
+
25
+ # Open a UNIX connection.
26
+ def initialize(socket_path, &block)
27
+ @socket = if block
28
+ ::UNIXSocket.open(socket_path, &block)
29
+ else
30
+ ::UNIXSocket.new(socket_path)
31
+ end
32
+ end
33
+
34
+ def to_io
35
+ @socket
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ # mini bundler, for embedded server gem installation
2
+
3
+ gem 'celluloid', '~> 0.12.0'
4
+ gem 'celluloid-io', '~> 0.12.0'
5
+ gem 'nio4r'
6
+ gem 'facter'
7
+ gem 'timers'
8
+
9
+ gem 'state_machine'
10
+ gem 'activesupport', '~> 3.2.0'
11
+
12
+ gem 'i18n' # for as
13
+ gem 'multi_json' # for as
@@ -0,0 +1,80 @@
1
+ require 'logger'
2
+
3
+ class Eye::Logger
4
+ attr_accessor :prefix, :subprefix
5
+
6
+ class InnerLogger < Logger
7
+ FORMAT = '%d.%m.%Y %H:%M:%S'
8
+
9
+ def initialize(*args)
10
+ super
11
+
12
+ self.formatter = Proc.new do |s, d, p, m|
13
+ "#{d.strftime(FORMAT)} #{s.ljust(5)} -- #{m}\n"
14
+ end
15
+ end
16
+ end
17
+
18
+ module Helpers
19
+ attr_reader :logger
20
+
21
+ Logger::Severity.constants.each do |level|
22
+ method_name = level.to_s.downcase
23
+ define_method method_name do |msg|
24
+ @logger.send(method_name, msg)
25
+ end
26
+ end
27
+ end
28
+
29
+ Logger::Severity.constants.each do |level|
30
+ method_name = level.to_s.downcase
31
+ define_method method_name do |msg|
32
+ self.class.inner_logger.send(method_name, "#{prefix_str}#{msg}")
33
+ end
34
+ end
35
+
36
+ def initialize(prefix = nil, subprefix = nil)
37
+ @prefix = prefix
38
+ @subprefix = subprefix
39
+ end
40
+
41
+ class << self
42
+ attr_reader :dev, :log_level
43
+
44
+ def link_logger(dev)
45
+ @dev = dev ? dev.to_s.downcase : nil
46
+ @dev_fd = @dev
47
+
48
+ @dev_fd = STDOUT if @dev == 'stdout'
49
+ @dev_fd = STDERR if @dev == 'stderr'
50
+
51
+ @inner_logger = InnerLogger.new(@dev_fd)
52
+ @inner_logger.level = self.log_level || Logger::INFO
53
+ end
54
+
55
+ def log_level=(level)
56
+ @log_level = level
57
+ @inner_logger.level = self.log_level if @inner_logger
58
+ end
59
+
60
+ def inner_logger
61
+ @inner_logger ||= InnerLogger.new(nil)
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def prefix_str
68
+ @pref_string ||= begin
69
+ pref_string = ''
70
+
71
+ if @prefix
72
+ pref_string = "[#{@prefix}] "
73
+ pref_string += "#{@subprefix} " if @subprefix
74
+ end
75
+
76
+ pref_string
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,83 @@
1
+ require 'celluloid'
2
+
3
+ class Eye::Process
4
+ include Celluloid
5
+
6
+ autoload :Config, 'eye/process/config'
7
+ autoload :Commands, 'eye/process/commands'
8
+ autoload :Data, 'eye/process/data'
9
+ autoload :Watchers, 'eye/process/watchers'
10
+ autoload :Monitor, 'eye/process/monitor'
11
+ autoload :System, 'eye/process/system'
12
+ autoload :Controller, 'eye/process/controller'
13
+ autoload :StatesHistory, 'eye/process/states_history'
14
+ autoload :Child, 'eye/process/child'
15
+ autoload :Trigger, 'eye/process/trigger'
16
+ autoload :Notify, 'eye/process/notify'
17
+ autoload :Scheduler, 'eye/process/scheduler'
18
+
19
+ attr_accessor :pid, :watchers, :config, :states_history,
20
+ :childs, :triggers, :flapping, :name
21
+
22
+ def initialize(config)
23
+ raise 'pid file should be' unless config[:pid_file]
24
+
25
+ @config = prepare_config(config)
26
+ @logger = Eye::Logger.new(full_name)
27
+
28
+ @watchers = {}
29
+ @childs = {}
30
+ @triggers = []
31
+ @flapping = false
32
+ @name = @config[:name]
33
+
34
+ @states_history = Eye::Process::StatesHistory.new(100)
35
+ @states_history << :unmonitored
36
+
37
+ debug "create with config: #{@config.inspect}"
38
+
39
+ add_triggers
40
+
41
+ super() # for statemachine
42
+ end
43
+
44
+ # c(), self[]
45
+ include Eye::Process::Config
46
+
47
+ # full_name, status_data
48
+ include Eye::Process::Data
49
+
50
+ # commands:
51
+ # start_process, stop_process, restart_process
52
+ include Eye::Process::Commands
53
+
54
+ # start, stop, restart, monitor, unmonit, delete
55
+ include Eye::Process::Controller
56
+
57
+ # add_watchers, remove_watchers:
58
+ include Eye::Process::Watchers
59
+
60
+ # check alive, crush methods:
61
+ include Eye::Process::Monitor
62
+
63
+ # system methods:
64
+ include Eye::Process::System
65
+
66
+ # manage childs methods
67
+ include Eye::Process::Child
68
+
69
+ # manage triggers methods
70
+ include Eye::Process::Trigger
71
+
72
+ # manage notify methods
73
+ include Eye::Process::Notify
74
+
75
+ # logger methods
76
+ include Eye::Logger::Helpers
77
+
78
+ # scheduler
79
+ include Eye::Process::Scheduler
80
+ end
81
+
82
+ # include state_machine states
83
+ require_relative 'process/states'
@@ -0,0 +1,61 @@
1
+ module Eye::Process::Child
2
+
3
+ def add_childs
4
+ add_or_update_childs
5
+ end
6
+
7
+ def add_or_update_childs
8
+ return unless self[:monitor_children]
9
+
10
+ return unless self.up?
11
+
12
+ unless self.pid
13
+ warn 'Cant add childs, because no pid'
14
+ return
15
+ end
16
+
17
+ now_childs = Eye::SystemResources.childs(self.pid)
18
+ new_childs = []
19
+ exist_childs = []
20
+
21
+ now_childs.each do |child_pid|
22
+ if self.childs[child_pid]
23
+ exist_childs << child_pid
24
+ else
25
+ new_childs << child_pid
26
+ end
27
+ end
28
+
29
+ removed_childs = self.childs.keys - now_childs
30
+
31
+ if new_childs.present?
32
+ new_childs.each do |child_pid|
33
+ self.childs[child_pid] = Eye::ChildProcess.new(child_pid, self[:monitor_children], logger.prefix)
34
+ end
35
+ end
36
+
37
+ if removed_childs.present?
38
+ removed_childs.each do |child_pid|
39
+ child = self.childs.delete(child_pid)
40
+ child.delete if child && child.alive?
41
+ end
42
+ end
43
+
44
+ h = {:new => new_childs.size, :removed => removed_childs.size, :exists => exist_childs.size }
45
+ debug "childs info: #{ h.inspect }"
46
+
47
+ h
48
+ end
49
+
50
+ def remove_childs
51
+ if childs.present?
52
+ childs.keys.each do |child_pid|
53
+ child = childs.delete(child_pid)
54
+ child.delete if child && child.alive?
55
+ end
56
+ else
57
+ debug 'No childs to clear'
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,256 @@
1
+ module Eye::Process::Commands
2
+
3
+ def start_process
4
+ debug 'start_process command'
5
+
6
+ switch :starting
7
+
8
+ unless self[:start_command]
9
+ warn 'no start command, so unmonitoring'
10
+ switch :unmonitoring
11
+ return :no_start_command
12
+ end
13
+
14
+ result = self[:daemonize] ? daemonize_process : execute_process
15
+
16
+ if !result[:error]
17
+ debug "process (#{self.pid}) ok started"
18
+ switch :started
19
+ else
20
+ debug "process (#{self.pid}) failed to start (#{result[:error].inspect})"
21
+ if self.pid && Eye::System.pid_alive?(self.pid)
22
+ warn "kill, what remains from process (#{self.pid}), because its failed to start (without pid_file impossible to monitoring)"
23
+ send_signal(:KILL)
24
+ sleep 0.2 # little grace
25
+ end
26
+
27
+ self.pid = nil
28
+ switch :crushed
29
+ end
30
+
31
+ result
32
+
33
+ rescue StateMachine::InvalidTransition => e
34
+ warn "wrong switch '#{e.message}'"
35
+
36
+ :state_error
37
+ end
38
+
39
+ def stop_process
40
+ debug 'stop_process command'
41
+
42
+ switch :stopping
43
+
44
+ kill_process
45
+
46
+ if process_realy_running?
47
+ warn 'NOT STOPPED, check command/signals, or tune stop_timeout/stop_grace, seems it was really soft'
48
+
49
+ switch :unmonitoring
50
+ nil
51
+
52
+ else
53
+ switch :stopped
54
+
55
+ if control_pid?
56
+ info "delete pid_file: #{self[:pid_file]}"
57
+ clear_pid_file
58
+ end
59
+
60
+ true
61
+
62
+ end
63
+
64
+ rescue StateMachine::InvalidTransition => e
65
+ warn "wrong switch '#{e.message}'"
66
+ nil
67
+ end
68
+
69
+ def restart_process
70
+ debug 'restart_process command'
71
+
72
+ switch :restarting
73
+
74
+ if self[:restart_command]
75
+ cmd = prepare_command(self[:restart_command])
76
+ info "executing: `#{cmd}` with restart_timeout: #{self[:restart_timeout].to_f}s and restart_grace: #{self[:restart_grace].to_f}s"
77
+
78
+ res = execute(cmd, config.merge(:timeout => self[:restart_timeout]))
79
+
80
+ if res[:error]
81
+ error "restart raised with #{res[:error].inspect}"
82
+
83
+ if res[:error].class == Timeout::Error
84
+ error 'you should tune restart_timeout setting'
85
+ end
86
+ end
87
+
88
+ sleep self[:restart_grace].to_f
89
+
90
+ result = check_alive_with_refresh_pid_if_needed
91
+ switch(result ? :restarted : :crushed)
92
+ else
93
+ stop_process
94
+ start_process
95
+ end
96
+
97
+ true
98
+
99
+ rescue StateMachine::InvalidTransition => e
100
+ warn "wrong switch '#{e.message}'"
101
+ nil
102
+ end
103
+
104
+ private
105
+
106
+ def kill_process
107
+ return unless self.pid
108
+
109
+ if self[:stop_command]
110
+ cmd = prepare_command(self[:stop_command])
111
+ res = execute(cmd, config.merge(:timeout => self[:stop_timeout]))
112
+ info "executing: `#{cmd}` with stop_timeout: #{self[:stop_timeout].to_f}s and stop_grace: #{self[:stop_grace].to_f}s"
113
+
114
+ if res[:error]
115
+ error "raised with #{res[:error].inspect}"
116
+
117
+ if res[:error].class == Timeout::Error
118
+ error 'you should tune stop_timeout setting'
119
+ end
120
+ end
121
+
122
+ sleep self[:stop_grace].to_f
123
+
124
+ elsif self[:stop_signals]
125
+ info "executing signals `#{self[:stop_signals].inspect}`"
126
+ stop_signals = self[:stop_signals].clone
127
+
128
+ signal = stop_signals.shift
129
+ send_signal(signal)
130
+
131
+ while stop_signals.present?
132
+ delay = stop_signals.shift
133
+ signal = stop_signals.shift
134
+
135
+ sleep(delay.to_f)
136
+ unless process_realy_running?
137
+ info 'has terminated'
138
+ break
139
+ end
140
+
141
+ send_signal(signal)
142
+ end
143
+
144
+ sleep self[:stop_grace].to_f
145
+
146
+ else # default command
147
+ info "executing: `kill -TERM #{self.pid}` with stop_grace: #{self[:stop_grace].to_f}s"
148
+ send_signal(:TERM)
149
+
150
+ sleep self[:stop_grace].to_f
151
+
152
+ # if process not die here, by default we kill it force
153
+ if process_realy_running?
154
+ warn "process not die after TERM and stop_grace #{self[:stop_grace].to_f}s, so send KILL"
155
+ send_signal(:KILL)
156
+ sleep 0.1 # little grace
157
+ end
158
+ end
159
+ end
160
+
161
+ def daemonize_process
162
+ time_before = Time.now
163
+ res = Eye::System.daemonize(self[:start_command], config)
164
+ start_time = Time.now - time_before
165
+
166
+ info "daemonizing: `#{self[:start_command]}` with start_grace: #{self[:start_grace].to_f}s, env: #{self[:environment].inspect}, working_dir: #{self[:working_dir]}"
167
+
168
+
169
+ if res[:error]
170
+ error "raised with #{res[:error].inspect}"
171
+
172
+ if res[:error].message == 'Permission denied - open'
173
+ error 'seems stdout/err/all files is not writable'
174
+ end
175
+
176
+ return {:error => res[:error].inspect}
177
+ end
178
+
179
+ self.pid = res[:pid]
180
+
181
+ unless self.pid
182
+ error 'returned empty pid, WTF O_o'
183
+ return {:error => :empty_pid}
184
+ end
185
+
186
+ sleep self[:start_grace].to_f
187
+
188
+ unless process_realy_running?
189
+ error "process with pid (#{self.pid}) not found, may be crushed (#{check_logs_str})"
190
+ return {:error => :not_realy_running}
191
+ end
192
+
193
+ begin
194
+ save_pid_to_file
195
+ rescue => ex
196
+ error "save pid to file raised with #{ex.inspect}"
197
+ return {:error => :cant_write_pid}
198
+ end
199
+
200
+ res
201
+ end
202
+
203
+ def execute_process
204
+ info "executing: `#{self[:start_command]}` with start_timeout: #{config[:start_timeout].to_f}s, start_grace: #{self[:start_grace].to_f}s, env: #{self[:environment].inspect}, working_dir: #{self[:working_dir]}"
205
+ time_before = Time.now
206
+
207
+ res = execute(self[:start_command], config.merge(:timeout => config[:start_timeout]))
208
+ start_time = Time.now - time_before
209
+
210
+ if res[:error]
211
+ error "raised with #{res[:error].inspect}"
212
+
213
+ if res[:error].message == 'Permission denied - open'
214
+ error 'seems stdout/err/all files is not writable'
215
+ end
216
+
217
+ if res[:error].class == Timeout::Error
218
+ error "try to increase start_timeout interval (current #{self[:start_timeout]} seems too small, for process self-daemonization)"
219
+ end
220
+
221
+ return {:error => res[:error].inspect}
222
+ end
223
+
224
+ sleep self[:start_grace].to_f
225
+
226
+ unless set_pid_from_file
227
+ error "pid_file(#{self[:pid_file]}) does not appears after start_grace #{self[:start_grace].to_f}, check start_command, or tune start_grace (eye dont know what to monitor without pid)"
228
+ return {:error => :pid_not_found}
229
+ end
230
+
231
+ unless process_realy_running?
232
+ error "process in pid_file(#{self[:pid_file]})(#{self.pid}) not found, maybe process do not write there actual pid, or just crushed (#{check_logs_str})"
233
+ return {:error => :not_realy_running}
234
+ end
235
+
236
+ res[:pid] = self.pid
237
+ res
238
+ end
239
+
240
+ def check_logs_str
241
+ if !self[:stdout] && !self[:stderr]
242
+ 'maybe should add stdout/err/all logs'
243
+ else
244
+ "check also it stdout/err/all logs #{[self[:stdout], self[:stderr]].inspect}"
245
+ end
246
+ end
247
+
248
+ def prepare_command(command)
249
+ if self.pid
250
+ command.to_s.gsub('{{PID}}', self.pid.to_s).gsub('{PID}', self.pid.to_s)
251
+ else
252
+ command
253
+ end
254
+ end
255
+
256
+ end