aggkit 0.3.8.9036 → 0.4.0.9098

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: 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