aggkit 0.3.8.9036 → 0.4.0.9098

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: 0f6196bc283eb4ae7ebc271822bee2b859e9dfbe
4
- data.tar.gz: d652c25bc8c40fbb203bb6f0339bd375113982b9
3
+ metadata.gz: d61521bee578abba7b80c9ad0182aae2483d42ca
4
+ data.tar.gz: a55d378ef1f3a44cd9a562cb9857aab3d7ab318f
5
5
  SHA512:
6
- metadata.gz: d9959a89a2ece7d74008f8c5b3ebf64f170b4cac72ee4f9b9ee4a5c9b8c29c78085898451accf280472dbfa1efaa91e4753b7f32ed0dcdb2e7399e7211460851
7
- data.tar.gz: fd1a2fa29e6bff027cdd41721477d71d0ae39ba2423175bb12b7059db74d650e431896fb85d13cdd840bb45eec013f185dbfbe3d20676543745881a0674754f1
6
+ metadata.gz: 970126d8a53f24b3a75f3317d4bd3db962540cae8eedcaa74ba33e0fa9d726837e0d975484c9dc9166566027527a25de31197bdd761f521ea317e277c2957bfb
7
+ data.tar.gz: c3082b9794e11ded61f6a67ef2826dfa3626533f596a5dd3bf464527774c973f23cf4c82b81ad20c8bd81d664fe835fb6915d2d1c3f737ba15f9322499d5d124
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- aggkit (0.3.8.9036)
4
+ aggkit (0.4.0.9098)
5
5
  diplomat
6
6
  dotenv
7
7
  json
@@ -12,9 +12,8 @@ GEM
12
12
  specs:
13
13
  awesome_print (1.8.0)
14
14
  diff-lcs (1.3)
15
- diplomat (2.0.2)
15
+ diplomat (2.0.5)
16
16
  faraday (~> 0.9)
17
- json
18
17
  dotenv (2.7.1)
19
18
  faraday (0.15.4)
20
19
  multipart-post (>= 1.2, < 3)
data/bin/aggconsul CHANGED
@@ -13,7 +13,7 @@ if ENV['CONSUL_HTTP_ADDR'].to_s.empty?
13
13
  end
14
14
 
15
15
  @opts = {
16
- consul: ENV['CONSUL_HTTP_ADDR']
16
+ consul: ENV['CONSUL_HTTP_ADDR']
17
17
  }
18
18
 
19
19
  @opts[:exec] = (begin
@@ -26,12 +26,12 @@ parser = OptionParser.new do |o|
26
26
  o.banner = 'Usage: consul.rb [options] -- exec'
27
27
 
28
28
  o.on('--consul url', 'Set up a custom Consul URL') do |consul|
29
- if consul.to_s['http']
30
- ENV['CONSUL_HTTP_ADDR'] = consul.to_s
29
+ ENV['CONSUL_HTTP_ADDR'] = if consul.to_s['http']
30
+ consul.to_s
31
31
  else
32
- ENV['CONSUL_HTTP_ADDR'] = "http://#{consul.to_s}:8500"
32
+ "http://#{consul}:8500"
33
33
  end
34
-
34
+
35
35
  @opts[:consul] = ENV['CONSUL_HTTP_ADDR']
36
36
  end
37
37
 
data/bin/aggstart CHANGED
@@ -31,12 +31,12 @@ parser = Aggkit::OptionParser.new do |o|
31
31
  end
32
32
 
33
33
  o.on("--consul=#{@opts[:consul]}", 'Set consul http address. CONSUL_HTTP_ADDR env can be used instead') do |consul|
34
- if consul.to_s['http']
35
- ENV['CONSUL_HTTP_ADDR'] = consul.to_s
34
+ ENV['CONSUL_HTTP_ADDR'] = if consul.to_s['http']
35
+ consul.to_s
36
36
  else
37
- ENV['CONSUL_HTTP_ADDR'] = "http://#{consul.to_s}:8500"
37
+ "http://#{consul}:8500"
38
38
  end
39
-
39
+
40
40
  @opts[:consul] = ENV['CONSUL_HTTP_ADDR']
41
41
  end
42
42
 
data/bin/aggterm CHANGED
@@ -12,7 +12,7 @@ STDERR.sync = true
12
12
  }
13
13
 
14
14
  def log(msg)
15
- puts "[terminator]: #{msg}"
15
+ puts "[terminator:#{::Process.pid}][#{Time.now.strftime('%H:%M:%S.%L')}]: #{msg}"
16
16
  end
17
17
 
18
18
  log "started: #{ARGV.inspect}"
@@ -40,6 +40,10 @@ parser = OptionParser.new do |o|
40
40
  o.on('--kill', 'SIGKILL self') do
41
41
  @opts[:kill] = true
42
42
  end
43
+
44
+ o.on('--fork NUM', 'fork NUM suprocesses and wait') do |num|
45
+ @opts[:fork] = Integer(num.to_s)
46
+ end
43
47
  end
44
48
  parser.parse!
45
49
 
@@ -53,6 +57,29 @@ parser.parse!
53
57
  end
54
58
  end
55
59
 
60
+ if @opts[:fork]
61
+ log 'forking...'
62
+ pids = @opts[:fork].times.map do |i|
63
+ fork do
64
+ exec 'echo', "#{i} forked"
65
+ end
66
+ end
67
+ sleep 1
68
+ pids.each do |pid|
69
+ pid, status = ::Process.wait2(pid, Process::WNOHANG)
70
+
71
+ if status.nil?
72
+ log 'child already collected'
73
+ exit 1
74
+ end
75
+
76
+ unless status.success?
77
+ log 'child crashed'
78
+ exit 2
79
+ end
80
+ end
81
+ end
82
+
56
83
  log 'sleep...'
57
84
  sleep @opts[:sleep]
58
85
 
@@ -67,6 +94,7 @@ if @opts[:term]
67
94
  ::Process.kill('TERM', $PROCESS_ID)
68
95
  end
69
96
 
97
+
70
98
  log "normal exit with: #{@opts[:code]}"
71
99
  exit @opts[:code]
72
100
 
data/bin/aggwrap CHANGED
@@ -6,8 +6,10 @@ require 'aggkit'
6
6
  require 'net/http'
7
7
 
8
8
  module Diplomat
9
+
9
10
  # Methods for interacting with the Consul check API endpoint
10
11
  class Check < Diplomat::RestClient
12
+
11
13
  # Update a TTL check
12
14
  # @param check_id [String] the unique id of the check
13
15
  # @param status [String] status of the check. Valid values are "passing", "warning", and "critical"
@@ -44,7 +46,9 @@ module Diplomat
44
46
  def fail(check_id, output = nil)
45
47
  update_ttl(check_id, 'critical', output)
46
48
  end
49
+
47
50
  end
51
+
48
52
  end
49
53
 
50
54
 
@@ -61,7 +65,7 @@ end
61
65
  @opts = {
62
66
  service: ENV['AGGREDATOR_SERVICE'],
63
67
  id: SecureRandom.hex(8),
64
- consul: ENV['CONSUL_HTTP_ADDR'],
68
+ consul: ENV['CONSUL_HTTP_ADDR']
65
69
  }
66
70
 
67
71
  @opts[:exec] = (begin
@@ -83,12 +87,12 @@ parser = Aggkit::OptionParser.new do |o|
83
87
  end
84
88
 
85
89
  o.on("--consul=#{@opts[:consul]}", 'Set consul host. CONSUL_HOST env used when missed') do |consul|
86
- if consul.to_s['http']
87
- ENV['CONSUL_HTTP_ADDR'] = consul.to_s
90
+ ENV['CONSUL_HTTP_ADDR'] = if consul.to_s['http']
91
+ consul.to_s
88
92
  else
89
- ENV['CONSUL_HTTP_ADDR'] = "http://#{consul.to_s}:8500"
93
+ "http://#{consul}:8500"
90
94
  end
91
-
95
+
92
96
  @opts[:consul] = ENV['CONSUL_HTTP_ADDR']
93
97
  end
94
98
 
@@ -114,7 +118,7 @@ die 'service name must be provided' if @opts[:service].to_s.empty?
114
118
 
115
119
  die 'script must be provided' if @opts[:exec].empty?
116
120
 
117
-
121
+
118
122
  Diplomat.configure do |config|
119
123
  config.url = @opts[:consul]
120
124
  end
data/lib/aggkit.rb CHANGED
@@ -5,10 +5,11 @@ require 'dotenv'
5
5
 
6
6
  require 'aggkit/version'
7
7
  require 'aggkit/option_parser'
8
+ require 'aggkit/childprocess'
8
9
  require 'aggkit/watcher'
9
10
  require 'aggkit/runner'
10
11
  require 'aggkit/env'
11
- require 'aggkit/childprocess'
12
+
12
13
 
13
14
  module Aggkit
14
15
 
@@ -5,6 +5,8 @@ module ChildProcess
5
5
 
6
6
  attr_reader :exit_code
7
7
 
8
+ attr_reader :status
9
+
8
10
  #
9
11
  # Set this to true if you do not care about when or if the process quits.
10
12
  #
@@ -74,6 +74,7 @@ module ChildProcess
74
74
  end
75
75
 
76
76
  def set_exit_code(status)
77
+ @status = status
77
78
  @exit_code = status.exitstatus || status.termsig
78
79
  end
79
80
 
data/lib/aggkit/runner.rb CHANGED
@@ -47,14 +47,25 @@ module Aggkit
47
47
 
48
48
  def execute(cmd)
49
49
  puts "Executing: #{cmd}"
50
- output = `#{cmd}`
50
+ io = IO.popen(cmd)
51
+ output = io.read
52
+ begin
53
+ io.close
54
+ rescue StandardError
55
+ nil
56
+ end
51
57
  @last_result = $?
52
58
  output
53
59
  end
54
60
 
55
61
  def execute!(cmd, error = nil)
56
62
  output = execute(cmd)
57
- ($? || @last_result).success? || die(error || "Can't execute: #{cmd}")
63
+ if @last_result
64
+ @last_result.success? || die(error || "Can't execute: #{cmd}")
65
+ else
66
+ die("Already collected: #{cmd}")
67
+ end
68
+
58
69
  output
59
70
  end
60
71
 
@@ -1,6 +1,6 @@
1
1
  module Aggkit
2
2
 
3
- VERSION = '0.3.8'.freeze
3
+ VERSION = '0.4.0'.freeze
4
4
 
5
5
  end
6
6
 
@@ -5,235 +5,207 @@ module Aggkit
5
5
 
6
6
  class Watcher
7
7
 
8
+ require 'aggkit/watcher/process_handler'
9
+
10
+ attr_accessor :iolock
11
+
12
+ EXIT_SIGNALS = %w[EXIT QUIT].freeze
13
+ TERM_SIGNALS = %w[INT TERM].freeze
14
+
15
+ class Pipe
16
+
17
+ def initialize
18
+ @read, @write = IO.pipe
19
+ end
20
+
21
+ def puts(str)
22
+ @write.puts str.to_s
23
+ end
24
+
25
+ def gets
26
+ @read.gets.strip.to_sym
27
+ end
28
+
29
+ end
8
30
 
9
31
  def initialize
10
- @lock = Mutex.new
32
+ @iolock = Mutex.new
33
+ @pipe = Pipe.new
11
34
 
12
35
  @procs = []
13
36
  @code = 0
14
37
  @crashed = false
15
- @threads = []
16
38
  @who = nil
17
- @stopping = false
18
- end
39
+ end
19
40
 
20
- def stop_all
21
- @stopping = true
41
+ def add(*cmd)
42
+ log "Starting #{cmd}..."
43
+ @procs.push ProcessHandler.new(self, *cmd)
44
+ log " * PID: #{@procs.last.pid}"
45
+ @procs.last
46
+ end
22
47
 
23
- terminating = @procs.reject do |meta|
24
- meta[:handled] || meta[:process].exited?
25
- end
48
+ def log(msg)
49
+ @iolock.synchronize{ STDOUT.puts("[watcher][#{Time.now.strftime('%H:%M:%S.%L')}]: #{msg}") }
50
+ end
26
51
 
27
- terminating.each do |meta|
28
- begin
29
- meta[:stdin].close
30
- rescue StandardError
31
- nil
32
- end
33
- if meta[:termcmd].is_a? String
34
- log "Terminating by #{meta[:termcmd].gsub('%PID%', meta[:process].pid.to_s)}..."
35
- output = `#{meta[:termcmd].gsub('%PID%', meta[:process].pid.to_s)}`
36
- if $?.success?
37
- log "ok: #{output}"
38
- else
39
- log "Error: #{output}"
40
- ::Process.kill 'TERM', meta[:process].pid
41
- end
42
- else
43
- ::Process.kill 'TERM', meta[:process].pid
44
- end
45
- end
52
+ def error(msg)
53
+ @iolock.synchronize{ STDERR.puts("[watcher][#{Time.now.strftime('%H:%M:%S.%L')}]: Error: #{msg}") }
54
+ end
46
55
 
47
- terminating.each do |meta|
48
- begin
49
- meta[:process].poll_for_exit(5)
50
- rescue ChildProcess::TimeoutError
51
- meta[:process].stop(1)
52
- meta[:stdout].close
53
- meta[:stderr].close
54
- end
56
+ def set_crash_report(pr)
57
+ unless @crashed
58
+ @crashed = true
59
+ @code = pr.exit_code
60
+ @who = pr.command
55
61
  end
62
+ end
56
63
 
57
- unless @crashed
58
- meta = @procs.detect do |meta|
59
- meta[:process].crashed?
60
- end
64
+ def quit!
65
+ @code = [@code || 0, 1].max if @crashed
66
+ exit!(@code || 0)
67
+ end
61
68
 
62
- if meta
63
- @crashed = true
64
- @code = meta[:process].exit_code
65
- @who = meta[:cmd]
66
- end
67
- end
69
+ def terminate_all
70
+ raise 'Double termination occured!' if $terminating
68
71
 
69
- @procs.each do |meta|
70
- begin
71
- meta[:stdout].close
72
- rescue StandardError
73
- nil
74
- end
75
- begin
76
- meta[:stderr].close
77
- rescue StandardError
78
- nil
79
- end
80
- end
72
+ $terminating = true
73
+ running = @procs.reject(&:handled?)
81
74
 
82
- Thread.new do
83
- sleep 2
84
- @threads.each(&:terminate)
85
- end
75
+ running.each do |pr|
76
+ begin
77
+ pr.stdin.close
78
+ rescue StandardError
79
+ nil
86
80
  end
87
-
88
- def add(*cmd)
89
- options = cmd.last
90
- if options.is_a? Hash
91
- cmd.pop
92
- else
93
- options = {}
81
+ pr.terminate
94
82
  end
95
83
 
96
- cmd = cmd.flatten.map{|c| c.to_s.strip }.reject(&:empty?)
97
- process = ChildProcess.build(*cmd)
84
+ running.each do |pr|
85
+ pr.stop
86
+ collect_managed(pr)
87
+ end
88
+ end
98
89
 
99
- rerr, werr = IO.pipe
100
- rout, wout = IO.pipe
90
+ def exec
91
+ install_signal_handlers(@pipe)
101
92
 
102
- process.io.stdout = wout
103
- process.io.stderr = werr
104
- process.duplex = true
93
+ begin
94
+ yield(self)
95
+ rescue StandardError => e
96
+ @crashed = true
97
+ @code = 1
98
+ error e.inspect
99
+ error e.backtrace.last(20).join("\n")
100
+ log 'Try exits gracefully..'
101
+ terminate_all
102
+ exit!(@code)
103
+ end
105
104
 
106
- meta = {
107
- cmd: cmd,
108
- process: process,
109
- stdout: rout,
110
- stderr: rerr,
111
- stdin: process.io.stdin,
112
- termcmd: options[:termcmd]
113
- }
105
+ loop_childs
106
+ quit! if @procs.all?(&:handled?)
114
107
 
115
- @threads << Thread.new(meta[:stdout], STDOUT) do |io, out|
108
+ Thread.new(@pipe) do |pipe|
116
109
  loop do
117
- break unless synchro_readline(io, out)
110
+ begin
111
+ sleep 10
112
+ pipe.puts :gc
113
+ rescue StandardError => e
114
+ log "GC thread exception: #{e.inspect}"
115
+ end
118
116
  end
119
117
  end
120
118
 
121
- @threads << Thread.new(meta[:stderr], STDERR) do |io, out|
122
- loop do
123
- break unless synchro_readline(io, out)
119
+ loop do
120
+ log 'Main loop...'
121
+ case event = @pipe.gets
122
+ when :term
123
+ log ' * Child terminated: try exits gracefully...'
124
+ terminate_all
125
+ loop_childs
126
+ quit!
127
+ when *(EXIT_SIGNALS + TERM_SIGNALS).map(&:to_sym)
128
+ log " * Catch #{event}: try exits gracefully..."
129
+ terminate_all
130
+ loop_childs
131
+ quit!
132
+ when :child, :gc
133
+ log " * Main loop event: #{event}"
134
+ loop_childs
135
+ quit! if @procs.all?(&:handled?)
136
+ else
137
+ log " * Unknown event: #{event.inspect}"
138
+ loop_childs
139
+ quit! if @procs.all?(&:handled?)
124
140
  end
125
141
  end
126
-
127
- log "Starting #{meta[:cmd]}"
128
- meta[:pid] = meta[:process].start.pid
129
-
130
- @procs.push(meta)
131
- meta
132
142
  end
133
143
 
134
- def synchro_readline(io, out)
135
- str = io.gets
136
- @lock.synchronize{ out.puts str }
137
- true
138
- rescue StandardError => e
139
- false
140
- end
144
+ private
141
145
 
142
- def log(msg)
143
- puts "[watcher]: #{msg}"
144
- end
146
+ def collect_managed(pr, status = nil)
147
+ log 'Child finished'
148
+ log " Process[#{pr.pid}]: #{pr.command}"
149
+ log " status: #{(status || pr.status).inspect}"
145
150
 
146
- def error(msg)
147
- STDERR.puts "[watcher]: Error: #{msg}"
148
- end
151
+ pr.stop!(status) if status
149
152
 
150
- def exec
151
- %w[EXIT QUIT].each do |sig|
152
- trap(sig) do
153
- stop_all
154
- end
153
+ set_crash_report(pr) if pr.crashed?
155
154
  end
156
155
 
156
+ def collect_processes
157
+ pid, status = Process.waitpid2(-1, ::Process::WNOHANG | ::Process::WUNTRACED)
157
158
 
158
- %w[INT TERM].each do |sig|
159
- trap(sig) do
160
- log "Catch #{sig}: try exits gracefully.."
161
- stop_all
159
+ return false if pid.nil? || pid == 0
160
+
161
+ if pr = @procs.find {|pr| pr.pid == pid }
162
+ collect_managed(pr, status)
163
+ @pipe.puts :term
164
+ else
165
+ log "Unmanaged process finished: #{status.inspect}"
162
166
  end
167
+
168
+ true
169
+ rescue Errno::ECHILD, Errno::ESRCH
170
+ false
163
171
  end
164
172
 
165
- trap('CLD') do |*_args|
166
- unhandled = @procs.reject do |meta|
167
- meta[:handled] || !meta[:process].exited?
173
+ def loop_childs
174
+ loop do
175
+ collected = collect_processes
176
+ break unless collected
168
177
  end
178
+ end
169
179
 
170
- completed = unhandled.any? do |meta|
171
- log 'Child finished'
172
- log " Process[#{meta[:pid]}]: #{meta[:cmd]}"
173
- log " status: #{meta[:process].crashed? ? 'crashed' : 'exited'}"
174
- log " code: #{meta[:process].exit_code}"
180
+ def install_signal_handlers(pipe)
181
+ EXIT_SIGNALS.each do |sig|
182
+ trap(sig) do |*_args|
183
+ EXIT_SIGNALS.each do |sig|
184
+ trap(sig, 'IGNORE')
185
+ end
175
186
 
176
- meta[:handled] = true
177
- begin
178
- meta[:stdin].close
179
- rescue StandardError
180
- nil
181
- end
182
- begin
183
- meta[:stdout].close
184
- rescue StandardError
185
- nil
186
- end
187
- begin
188
- meta[:stderr].close
189
- rescue StandardError
190
- nil
187
+ pipe.puts sig
191
188
  end
189
+ end
192
190
 
193
- if !@crashed && meta[:process].crashed?
194
- @crashed = true
195
- @code = meta[:process].exit_code
196
- @who = meta[:cmd]
197
- end
191
+ TERM_SIGNALS.each do |sig|
192
+ trap(sig) do |*_args|
193
+ TERM_SIGNALS.each do |sig|
194
+ trap(sig) do |*_args|
195
+ STDERR.puts 'Forcing exit!'
196
+ exit!(1)
197
+ end
198
+ end
198
199
 
199
- unless @stopping
200
- log 'Try exits gracefully..'
201
- stop_all
200
+ pipe.puts sig
202
201
  end
203
-
204
- true
205
202
  end
206
203
 
207
- unless completed
208
- begin
209
- pid, status = Process.waitpid2(-1, Process::WNOHANG)
210
- rescue StandardError
211
- nil
212
- end
213
- log "Subprocess finished: #{status.inspect}" if status
204
+ trap('CLD') do |*_args|
205
+ pipe.puts :child
214
206
  end
215
207
  end
216
208
 
217
- begin
218
- yield(self)
219
- rescue StandardError => e
220
- @crashed = true
221
- @code = 1
222
- error e.inspect
223
- error e.backtrace.last(20).join("\n")
224
- log 'Try exits gracefully..'
225
- stop_all
226
- end
227
-
228
- @threads.map(&:join)
229
-
230
- @code = [@code || 0, 1].max if @crashed
231
-
232
- exit(@code || 0)
233
- end
234
-
235
-
236
-
237
209
  end
238
210
 
239
211
  end
@@ -0,0 +1,172 @@
1
+ require 'English'
2
+
3
+ class Aggkit::Watcher::ProcessHandler
4
+
5
+ attr_accessor :watcher, :command, :options, :process, :stdin, :stdout, :stderr
6
+
7
+ def self.capture(cmd)
8
+ io = IO.popen(cmd)
9
+ output = io.read
10
+ begin
11
+ io.close
12
+ rescue StandardError
13
+ nil
14
+ end
15
+ [output, $?]
16
+ end
17
+
18
+ def initialize(watcher, *cmd)
19
+ @watcher = watcher
20
+
21
+ @options = if cmd.last.is_a? Hash
22
+ cmd.pop
23
+ else
24
+ {}
25
+ end
26
+
27
+ @command = cmd.flatten.map{|c| c.to_s.strip }.reject(&:empty?)
28
+ @process = build_process(*command)
29
+
30
+ initialize_streams
31
+
32
+ @process.start
33
+ end
34
+
35
+ def initialize_streams
36
+ @threads = []
37
+
38
+ @threads << Thread.new do
39
+ loop do
40
+ break unless synchro_readline(stdout, STDOUT)
41
+ end
42
+ end
43
+
44
+ @threads << Thread.new do
45
+ loop do
46
+ break unless synchro_readline(stderr, STDERR)
47
+ end
48
+ end
49
+ end
50
+
51
+ def synchro_readline(io, out)
52
+ str = io.gets
53
+ @watcher.iolock.synchronize{ out.puts(str) }
54
+ true
55
+ rescue StandardError
56
+ false
57
+ end
58
+
59
+ def build_process(*cmd)
60
+ pr = ::Aggkit::ChildProcess.build(*cmd)
61
+ @stdout, wout = IO.pipe
62
+ @stderr, werr = IO.pipe
63
+
64
+ @stdin = pr.io.stdin
65
+
66
+ pr.io.stdout = wout
67
+ pr.io.stderr = werr
68
+ pr.duplex = true
69
+ pr
70
+ end
71
+
72
+ def handled?
73
+ !!@process.exit_code
74
+ end
75
+
76
+ def stop!(status)
77
+ @process.send(:set_exit_code, status)
78
+ stop
79
+ end
80
+
81
+ def terminate
82
+ return if exited?
83
+ return if @terminating
84
+
85
+ @terminating = true
86
+
87
+ if @options[:termcmd]
88
+ termcmd = @options[:termcmd].gsub('%PID%', pid.to_s)
89
+ @watcher.log "Terminating by #{termcmd}..."
90
+ output, status = ::Aggkit::Watcher::ProcessHandler.capture(termcmd)
91
+
92
+ if status.success?
93
+ @watcher.log "Success: #{output}"
94
+ else
95
+ @watcher.error "Failed: #{output}"
96
+ @process.send(:send_term)
97
+ end
98
+ else
99
+ @process.send(:send_term)
100
+ end
101
+ end
102
+
103
+ def stop(timeout = (@options[:timeout] || 5))
104
+ return if exited?
105
+
106
+ terminate
107
+
108
+ begin
109
+ return poll_for_exit(timeout)
110
+ rescue TimeoutError
111
+ # try next
112
+ end
113
+
114
+ begin
115
+ @process.send(:send_kill)
116
+ rescue Errno::ECHILD, Errno::ESRCH
117
+ # handle race condition where process dies between timeout
118
+ # and send_kill
119
+ end
120
+
121
+ wait
122
+ ensure
123
+ clean_all
124
+ end
125
+
126
+ def method_missing(m, *args, &block)
127
+ if @process.respond_to? m
128
+ @process.send(m, *args, &block)
129
+ else
130
+ super
131
+ end
132
+ end
133
+
134
+ private
135
+
136
+ def clean_all
137
+ begin
138
+ @stdin.close
139
+ rescue StandardError
140
+ nil
141
+ end
142
+
143
+ begin
144
+ @stdout.close
145
+ rescue StandardError
146
+ nil
147
+ end
148
+
149
+ begin
150
+ @stderr.close
151
+ rescue StandardError
152
+ nil
153
+ end
154
+
155
+ @threads.each do |th|
156
+ begin
157
+ th.terminate
158
+ rescue StandardError
159
+ nil
160
+ end
161
+ begin
162
+ th.join
163
+ rescue StandardError
164
+ nil
165
+ end
166
+ end
167
+
168
+ @threads = []
169
+ end
170
+
171
+ end
172
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aggkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8.9036
4
+ version: 0.4.0.9098
5
5
  platform: ruby
6
6
  authors:
7
7
  - Godko Ivan
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-02-27 00:00:00.000000000 Z
12
+ date: 2019-02-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: diplomat
@@ -171,6 +171,7 @@ files:
171
171
  - lib/aggkit/runner.rb
172
172
  - lib/aggkit/version.rb
173
173
  - lib/aggkit/watcher.rb
174
+ - lib/aggkit/watcher/process_handler.rb
174
175
  homepage: https://br.rnds.pro/aggredator/support/aggkit
175
176
  licenses:
176
177
  - MIT