eye 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
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,88 @@
1
+ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
2
+
3
+ STR_OPTIONS = [ :pid_file, :working_dir, :stdout, :stderr, :stdall, :start_command,
4
+ :stop_command, :restart_command ]
5
+
6
+ create_options_methods(STR_OPTIONS, String)
7
+
8
+ BOOL_OPTIONS = [ :daemonize, :keep_alive, :control_pid, :auto_start, :stop_on_delete]
9
+
10
+ create_options_methods(BOOL_OPTIONS, [TrueClass, FalseClass])
11
+
12
+ INTERVAL_OPTIONS = [ :check_alive_period, :start_timeout, :restart_timeout, :stop_timeout, :start_grace,
13
+ :restart_grace, :stop_grace, :childs_update_period ]
14
+
15
+ create_options_methods(INTERVAL_OPTIONS, [Fixnum, Float])
16
+
17
+ OTHER_OPTIONS = [ :environment, :stop_signals ]
18
+
19
+ create_options_methods(OTHER_OPTIONS)
20
+
21
+
22
+
23
+ def initialize(name = nil, parent = nil)
24
+ super(name, parent)
25
+
26
+ # ensure delete subobjects which can appears from parent config
27
+ @config.delete :groups
28
+ @config.delete :processes
29
+
30
+ @config[:application] = parent.name if parent.is_a?(Eye::Dsl::ApplicationOpts)
31
+ @config[:group] = parent.name if parent.is_a?(Eye::Dsl::GroupOpts)
32
+
33
+ # hack for full name
34
+ @full_name = parent.full_name if @name == '__default__'
35
+ end
36
+
37
+ def checks(type, opts = {})
38
+ type = type.to_sym
39
+ raise Eye::Dsl::Error, "unknown checker type #{type}" unless Eye::Checker::TYPES[type]
40
+
41
+ opts.merge!(:type => type)
42
+ Eye::Checker.validate!(opts)
43
+
44
+ @config[:checks] ||= {}
45
+ @config[:checks][type] = opts
46
+ end
47
+
48
+ def triggers(type, opts = {})
49
+ type = type.to_sym
50
+ raise Eye::Dsl::Error, "unknown trigger type #{type}" unless Eye::Trigger::TYPES[type]
51
+
52
+ opts.merge!(:type => type)
53
+ Eye::Trigger.validate!(opts)
54
+
55
+ @config[:triggers] ||= {}
56
+ @config[:triggers][type] = opts
57
+ end
58
+
59
+ # clear checks from parent
60
+ def nochecks(type)
61
+ type = type.to_sym
62
+ raise Eye::Dsl::Error, "unknown checker type #{type}" unless Eye::Checker::TYPES[type]
63
+ @config[:checks].try :delete, type
64
+ end
65
+
66
+ # clear triggers from parent
67
+ def notriggers(type)
68
+ type = type.to_sym
69
+ raise Eye::Dsl::Error, "unknown trigger type #{type}" unless Eye::Trigger::TYPES[type]
70
+ @config[:triggers].try :delete, type
71
+ end
72
+
73
+ def set_environment(value)
74
+ raise Eye::Dsl::Error, "environment should be a hash, but not #{value.inspect}" unless value.is_a?(Hash)
75
+ @config[:environment] ||= {}
76
+ @config[:environment].merge!(value)
77
+ end
78
+
79
+ alias :env :environment
80
+
81
+ def set_stdall(value)
82
+ super
83
+
84
+ set_stdout value
85
+ set_stderr value
86
+ end
87
+
88
+ end
@@ -0,0 +1,21 @@
1
+ class Eye::Dsl::ProcessOpts < Eye::Dsl::Opts
2
+
3
+ def monitor_children(&block)
4
+ opts = Eye::Dsl::ChildProcessOpts.new
5
+ opts.instance_eval(&block)
6
+ @config[:monitor_children] ||= {}
7
+ @config[:monitor_children].merge!(opts.config)
8
+ end
9
+
10
+ def xmonitor_children(&block); end
11
+
12
+ def application
13
+ parent.try(:parent)
14
+ end
15
+ alias :app :application
16
+
17
+ def group
18
+ parent
19
+ end
20
+
21
+ end
@@ -0,0 +1,132 @@
1
+ class Eye::Dsl::PureOpts
2
+
3
+ def self.create_options_methods(arr, types = nil)
4
+ m = Module.new do
5
+ arr.each do |opt|
6
+ define_method("set_#{opt}") do |arg|
7
+ key = opt.to_sym
8
+
9
+ if (disallow_options && disallow_options.include?(key)) || (allow_options && !allow_options.include?(key))
10
+ raise Eye::Dsl::Error, "disallow option #{key} for #{self.class.inspect}"
11
+ end
12
+
13
+ if types
14
+ good_type = Array(types).any?{|type| arg.is_a?(type) } || arg.nil?
15
+ raise Eye::Dsl::Error, "bad :#{opt} value #{arg.inspect}, type should be #{types.inspect}" unless good_type
16
+ end
17
+
18
+ @config[key] = arg
19
+ end
20
+
21
+ define_method("get_#{opt}") do
22
+ @config[ opt.to_sym ]
23
+ end
24
+
25
+ define_method(opt) do |*args|
26
+ if args.blank?
27
+ # getter
28
+ send "get_#{opt}"
29
+ else
30
+ send "set_#{opt}", *args
31
+ end
32
+ end
33
+
34
+ define_method("#{opt}=") do |arg|
35
+ send opt, arg
36
+ end
37
+ end
38
+ end
39
+
40
+ self.send :include, m
41
+ end
42
+
43
+ attr_reader :name, :full_name
44
+ attr_reader :config, :parent
45
+
46
+ def initialize(name = nil, parent = nil)
47
+ @name = name.to_s
48
+ @full_name = @name
49
+
50
+ if parent
51
+ @parent = parent
52
+ @config = Marshal.load(Marshal.dump(parent.config)) # O_o ruby recommended deep clone
53
+ @full_name = "#{parent.full_name}:#{@full_name}"
54
+ else
55
+ @config = {}
56
+ end
57
+
58
+ @config[:name] = @name if @name.present?
59
+ end
60
+
61
+ def allow_options
62
+ nil
63
+ end
64
+
65
+ def disallow_options
66
+ []
67
+ end
68
+
69
+ # execute part of config on particular server
70
+ # array of strings
71
+ # regexp
72
+ # string
73
+ def with_server(glob = nil, &block)
74
+ on_server = true
75
+
76
+ if glob.present?
77
+ host = Eye::System.host
78
+
79
+ if glob.is_a?(Array)
80
+ on_server = !!glob.any?{|elem| elem == host}
81
+ elsif glob.is_a?(Regexp)
82
+ on_server = !!host.match(glob)
83
+ elsif glob.is_a?(String) || glob.is_a?(Symbol)
84
+ on_server = (host == glob.to_s)
85
+ end
86
+ end
87
+
88
+ with_condition(on_server, &block)
89
+
90
+ on_server
91
+ end
92
+
93
+ def with_condition(cond = true, &block)
94
+ self.instance_eval(&block) if cond && block
95
+ end
96
+
97
+ def self.with_parsed_file(file_name)
98
+ saved_parsed_filename = Eye.parsed_filename
99
+
100
+ require 'pathname'
101
+
102
+ real_filename = Eye.parsed_filename && File.symlink?(Eye.parsed_filename) ? File.readlink(Eye.parsed_filename) : Eye.parsed_filename
103
+ dirname = File.dirname(real_filename) rescue nil
104
+ path = Pathname.new(file_name).expand_path(dirname).to_s
105
+
106
+ Eye.parsed_filename = path
107
+ yield path
108
+ ensure
109
+ Eye.parsed_filename = saved_parsed_filename
110
+ end
111
+
112
+ def include(proc, *args)
113
+ if proc.is_a?(String)
114
+ self.class.with_parsed_file(proc) do |path|
115
+ if File.exists?(path)
116
+ Eye::Dsl.debug "=> load #{path}"
117
+ self.instance_eval(File.read(path))
118
+ Eye::Dsl.debug "<= load #{path}"
119
+ end
120
+ end
121
+ else
122
+ ie = if args.present?
123
+ lambda{|i| proc[i, *args] }
124
+ else
125
+ proc
126
+ end
127
+
128
+ self.instance_eval(&ie)
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,41 @@
1
+ module Eye::Dsl::Validate
2
+
3
+ # validate global config rules
4
+ def validate(config)
5
+ cfg = config[:config]
6
+ config = config[:applications]
7
+
8
+ all_processes = config.values.map{|e| (e[:groups] || {}).values.map{|c| (c[:processes] || {}).values} }.flatten
9
+
10
+ # Check blank pid_files
11
+
12
+ no_pid_file = all_processes.select{|c| c[:pid_file].blank? }
13
+ if no_pid_file.present?
14
+ raise Eye::Dsl::Error, "blank pid_file for: #{no_pid_file.map{|c| c[:name]} * ', '}"
15
+ end
16
+
17
+ # Check dublicates of the full pid_file
18
+
19
+ dubl_pids = all_processes.each_with_object(Hash.new(0)) do |o, h|
20
+ ex_pid_file = Eye::System.normalized_file(o[:pid_file], o[:working_dir])
21
+ h[ex_pid_file] += 1
22
+ end
23
+ dubl_pids = dubl_pids.select{|k,v| v>1}
24
+
25
+ if dubl_pids.present?
26
+ raise Eye::Dsl::Error, "dublicate pid_files: #{dubl_pids.inspect}"
27
+ end
28
+
29
+ # Check dublicates of the full_name
30
+ dubl_names = all_processes.each_with_object(Hash.new(0)) do |o, h|
31
+ full_name = "#{o[:application]}:#{o[:group]}:#{o[:name]}"
32
+ h[full_name] += 1
33
+ end
34
+ dubl_names = dubl_names.select{|k,v| v>1}
35
+
36
+ if dubl_names.present?
37
+ raise Eye::Dsl::Error, "dublicate names: #{dubl_names.inspect}"
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,125 @@
1
+ require 'celluloid'
2
+
3
+ class Eye::Group
4
+ include Celluloid
5
+
6
+ autoload :Chain, 'eye/group/chain'
7
+
8
+ include Eye::Logger::Helpers
9
+ include Eye::Process::Scheduler
10
+ include Eye::Group::Chain
11
+
12
+ attr_reader :processes, :name, :hidden, :config
13
+
14
+ def initialize(name, config)
15
+ @name = name
16
+ @config = config
17
+ @logger = Eye::Logger.new(full_name)
18
+ @processes = Eye::Utils::AliveArray.new
19
+ @hidden = (name == '__default__')
20
+ debug 'created'
21
+ end
22
+
23
+ def full_name
24
+ @full_name ||= "#{@config[:application]}:#{@name}"
25
+ end
26
+
27
+ def update_config(cfg)
28
+ @config = cfg
29
+ @full_name = nil
30
+ end
31
+
32
+ def add_process(process)
33
+ @processes << process
34
+ end
35
+
36
+ # sort processes in name order
37
+ def resort_processes
38
+ @processes = @processes.sort_by(&:name)
39
+ end
40
+
41
+ def status_data(debug = false)
42
+ plist = @processes.map{|p| p.status_data(debug) }
43
+
44
+ h = { name: name, type: :group, subtree: plist }
45
+
46
+ h.merge!(debug: debug_data) if debug
47
+
48
+ # show current chain
49
+ if current_scheduled_command
50
+ h.update(current_command: current_scheduled_command)
51
+
52
+ if (chain_commands = scheduler_actions_list) && chain_commands.present?
53
+ h.update(chain_commands: chain_commands)
54
+ end
55
+
56
+ if @chain_processes_current && @chain_processes_count
57
+ h.update(chain_progress: [@chain_processes_current, @chain_processes_count])
58
+ end
59
+ end
60
+
61
+ h
62
+ end
63
+
64
+ def debug_data
65
+ {:queue => scheduler_actions_list, :chain => chain_status}
66
+ end
67
+
68
+ def send_command(command, *args)
69
+ info "send_command: #{command}"
70
+
71
+ if command == :delete
72
+ delete *args
73
+ else
74
+ schedule command, *args, "#{command} by user"
75
+ end
76
+ end
77
+
78
+ def start
79
+ chain_command :start
80
+ end
81
+
82
+ def stop
83
+ async_schedule :stop
84
+ end
85
+
86
+ def restart
87
+ chain_command :restart
88
+ end
89
+
90
+ def delete
91
+ async_schedule :delete
92
+ terminate
93
+ end
94
+
95
+ def monitor
96
+ chain_command :monitor
97
+ end
98
+
99
+ def unmonitor
100
+ async_schedule :unmonitor
101
+ end
102
+
103
+ def signal(sig)
104
+ async_schedule :signal, sig
105
+ end
106
+
107
+ def clear
108
+ @processes.clear
109
+ end
110
+
111
+ def sub_object?(obj)
112
+ @processes.include?(obj)
113
+ end
114
+
115
+ private
116
+
117
+ def async_schedule(command, *args)
118
+ info "send to all processes #{command} #{args.present? ? args*',' : nil}"
119
+
120
+ @processes.each do |process|
121
+ process.send_command(command, *args)
122
+ end
123
+ end
124
+
125
+ end
@@ -0,0 +1,68 @@
1
+ module Eye::Group::Chain
2
+
3
+ private
4
+
5
+ def chain_schedule(type, grace, command, *args)
6
+ info "start #{type} with #{grace}s chain #{command} #{args}"
7
+
8
+ @chain_processes_count = @processes.size
9
+ @chain_processes_current = 0
10
+
11
+ @processes.each do | process |
12
+ chain_schedule_process(process, type, command, *args)
13
+
14
+ @chain_processes_current = @chain_processes_current.to_i + 1
15
+
16
+ # to skip last sleep
17
+ break if @chain_processes_current.to_i == @chain_processes_count.to_i
18
+
19
+ # wait next process
20
+ sleep grace.to_f
21
+ end
22
+
23
+ @chain_processes_count = nil
24
+ @chain_processes_current = nil
25
+ end
26
+
27
+ def chain_schedule_process(process, type, command, *args)
28
+ if type == :sync
29
+ # sync command, with waiting
30
+ process.send(command, *args)
31
+ else
32
+ # async command
33
+ process.send_command(command, *args)
34
+ end
35
+ end
36
+
37
+ def chain_status
38
+ if @config[:chain]
39
+ [:start, :restart].map{|c| @config[:chain][c].try(:[], :grace) }
40
+ end
41
+ end
42
+
43
+ def chain_command(command, *args)
44
+ chain_opts = chain_options(command)
45
+ chain_schedule(chain_opts[:type], chain_opts[:grace], command, *args)
46
+ end
47
+
48
+ # with such delay will chained processes by default
49
+ DEFAULT_CHAIN = 0.2
50
+
51
+ def chain_options(command)
52
+ command = :start if command == :monitor # hack for monitor command, work as start
53
+
54
+ if @config[:chain] && @config[:chain][command]
55
+ type = @config[:chain][command].try :[], :type
56
+ type = [:async, :sync].include?(type) ? type : :async
57
+
58
+ grace = @config[:chain][command].try :[], :grace
59
+ grace = grace ? (grace.to_f rescue DEFAULT_CHAIN) : DEFAULT_CHAIN
60
+
61
+ {:type => type, :grace => grace}
62
+ else
63
+ # default chain case
64
+ {:type => :async, :grace => DEFAULT_CHAIN}
65
+ end
66
+ end
67
+
68
+ end