frontkick 0.5.0 → 0.5.1
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +37 -14
- data/example/kill_child.rb +49 -3
- data/lib/frontkick.rb +6 -2
- data/lib/frontkick/command.rb +11 -25
- data/lib/frontkick/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21315e4ecfde359617b02081d2252b558e576acd
|
4
|
+
data.tar.gz: 158fd87c5c96234c08ac944259b734d580f4a7bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cca5e9b8043cf202446b3592d3370f17b3d5bdbe490df40e0b82f90b852154e2c44e157e74a901ab26427ffcd07bf82ea43e9ecfca16a2840c3486d4e210252f
|
7
|
+
data.tar.gz: 0cba11a2c72e2be354087dfb9d79c4df17ee2b737c6ad1c19457ce6dc78488a53d43dfa3b7804ec9a3c74c04633b766177ec59e64877497a07a5f2cd1640a3d4
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -54,20 +54,7 @@ If you prefer to be blocked:
|
|
54
54
|
|
55
55
|
Frontkick.exec("sleep 2 && ls /hoge", :exclusive => "/tmp/frontkick.lock", :exclusive_blocking => true)
|
56
56
|
|
57
|
-
###
|
58
|
-
|
59
|
-
On receiving INT and TERM signal, kill the kicked child process before exiting
|
60
|
-
|
61
|
-
Frontkick.exec(["sleep 100"], :kill_child => true)
|
62
|
-
|
63
|
-
NOTE: This uses Kernel.trap inside.
|
64
|
-
NOTE: Shoud use `[]` form, otherwirse `sh -c 'sleep 100'` is ran, and frotkick kills sh process, but sleep process remains
|
65
|
-
|
66
|
-
### Spawn Options
|
67
|
-
|
68
|
-
Other options such as :chdir are treated as options of `Kernel.#spawn`. See http://ruby-doc.org/core-2.3.0/Kernel.html#method-i-spawn for available options.
|
69
|
-
|
70
|
-
### Redirect Options
|
57
|
+
### Redirect Options (:out and :err)
|
71
58
|
|
72
59
|
Frontkick.exec(["ls /something_not_found"], :out => 'stdout.txt', :err => 'stderr.txt')
|
73
60
|
|
@@ -79,6 +66,42 @@ This redirects STDOUT and STDERR into files. In this case, result.stdout, and re
|
|
79
66
|
|
80
67
|
You can also give IO objects. In this case, result.stdout, and result.stderr are the given IO objects.
|
81
68
|
|
69
|
+
### Popen3 Options (such as :chdir)
|
70
|
+
|
71
|
+
Other options such as :chdir are treated as options of `Open3.#popen3`.
|
72
|
+
|
73
|
+
### Kill Child Process
|
74
|
+
|
75
|
+
To kill your frontkick process with its kicked child process, send signal to their signal group as
|
76
|
+
|
77
|
+
kill -TERM -{PGID}
|
78
|
+
|
79
|
+
You can find PGID like `ps -eo pid,pgid,command`.
|
80
|
+
|
81
|
+
If you can not send a signal to a signal group by some reasons, handle signal by yourself as
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
Frontkick.exec(["sleep 100"]) do |wait_thr|
|
85
|
+
pid = wait_thr.pid
|
86
|
+
trap :INT do
|
87
|
+
Process.kill(:TERM, pid)
|
88
|
+
# wait child processes finish
|
89
|
+
begin
|
90
|
+
pid, status = Process.waitpid2(pid)
|
91
|
+
rescue Errno::ECHILD => e
|
92
|
+
end
|
93
|
+
exit 130
|
94
|
+
end
|
95
|
+
trap :TERM do
|
96
|
+
Process.kill(:TERM, pid)
|
97
|
+
Frontkick.process_wait(pid) # same with above
|
98
|
+
exit 143
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
More sophisticated example is available at [./example/kill_child.rb]
|
104
|
+
|
82
105
|
## Contributing
|
83
106
|
|
84
107
|
1. Fork it
|
data/example/kill_child.rb
CHANGED
@@ -1,5 +1,51 @@
|
|
1
1
|
require 'frontkick'
|
2
2
|
|
3
|
-
puts Process.pid
|
4
|
-
|
5
|
-
|
3
|
+
puts "kill -TERM #{Process.pid} or Hit Ctrl-C in 10 seconds"
|
4
|
+
|
5
|
+
result = Frontkick.exec(["sleep 10"]) do |wait_thr|
|
6
|
+
pid = wait_thr.pid
|
7
|
+
signal_pipe_r, signal_pipe_w = IO.pipe
|
8
|
+
|
9
|
+
# You know, there are many things `can't be called from trap context`
|
10
|
+
trap :INT do
|
11
|
+
signal_pipe_w.puts 'INT'
|
12
|
+
end
|
13
|
+
trap :TERM do
|
14
|
+
signal_pipe_w.puts 'TERM'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new thread to handle signals
|
18
|
+
# This example kills child and self
|
19
|
+
signal_handler_thr = Thread.new do
|
20
|
+
readable_io = IO.select([signal_pipe_r])
|
21
|
+
signal = readable_io.first[0].gets.strip
|
22
|
+
case signal
|
23
|
+
when 'INT'
|
24
|
+
puts "kill -INT #{pid}"
|
25
|
+
Process.kill('INT', pid) rescue nil
|
26
|
+
pid, status = Process.waitpid2(pid) rescue nil
|
27
|
+
Kernel.exit(130)
|
28
|
+
when 'TERM'
|
29
|
+
puts "kill -TERM #{pid}"
|
30
|
+
Process.kill('TERM', pid) rescue nil
|
31
|
+
pid, status = Process.waitpid2(pid) rescue nil
|
32
|
+
Kernel.exit(148)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
begin
|
37
|
+
# Wait child to finish (for normal situation)
|
38
|
+
wait_thr.join
|
39
|
+
|
40
|
+
# Send NOOP to finish signal_handler_thr (for normal situation)
|
41
|
+
signal_pipe_w.puts 'NOOP'
|
42
|
+
signal_handler_thr.join
|
43
|
+
ensure
|
44
|
+
signal_pipe_r.close rescue nil
|
45
|
+
signal_pipe_w.close rescue nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# should come here if child process finished normally,
|
50
|
+
# but not come here if signals are received (Kernel.exit)
|
51
|
+
puts result.inspect
|
data/lib/frontkick.rb
CHANGED
@@ -5,7 +5,11 @@ require 'frontkick/command'
|
|
5
5
|
require 'frontkick/result'
|
6
6
|
|
7
7
|
module Frontkick
|
8
|
-
def self.exec(cmd, opts = {})
|
9
|
-
::Frontkick::Command.exec(cmd, opts)
|
8
|
+
def self.exec(cmd, opts = {}, &block)
|
9
|
+
::Frontkick::Command.exec(cmd, opts, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.process_wait(pid)
|
13
|
+
::Frontkick::Command.process_wait(pid)
|
10
14
|
end
|
11
15
|
end
|
data/lib/frontkick/command.rb
CHANGED
@@ -4,7 +4,7 @@ require 'shellwords'
|
|
4
4
|
|
5
5
|
module Frontkick
|
6
6
|
class Command
|
7
|
-
def self.exec(cmd, opts = {})
|
7
|
+
def self.exec(cmd, opts = {}, &block)
|
8
8
|
opts[:timeout_kill] = true unless opts.has_key?(:timeout_kill) # default: true
|
9
9
|
|
10
10
|
exit_code, duration = nil
|
@@ -39,14 +39,14 @@ module Frontkick
|
|
39
39
|
return Result.new(:stdout => command, :stderr => '', :exit_code => 0, :duration => 0)
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
popen3_opts = self.popen3_opts(opts)
|
43
43
|
|
44
44
|
lock_fd = file_lock(opts[:exclusive], opts[:exclusive_blocking]) if opts[:exclusive]
|
45
45
|
begin
|
46
46
|
::Timeout.timeout(opts[:timeout], Frontkick::TimeoutLocal) do # nil is for no timeout
|
47
47
|
duration = Benchmark.realtime do
|
48
|
-
stdin, stdout, stderr, wait_thr = Open3.popen3(*cmd_array,
|
49
|
-
|
48
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(*cmd_array, popen3_opts)
|
49
|
+
out_thr = Thread.new {
|
50
50
|
begin
|
51
51
|
while true
|
52
52
|
out.write stdout.readpartial(4096)
|
@@ -54,7 +54,7 @@ module Frontkick
|
|
54
54
|
rescue EOFError
|
55
55
|
end
|
56
56
|
}
|
57
|
-
|
57
|
+
err_thr = Thread.new {
|
58
58
|
begin
|
59
59
|
while true
|
60
60
|
err.write stderr.readpartial(4096)
|
@@ -65,12 +65,10 @@ module Frontkick
|
|
65
65
|
stdin.close
|
66
66
|
pid = wait_thr.pid
|
67
67
|
|
68
|
-
if
|
69
|
-
trap_signal(pid)
|
70
|
-
end
|
68
|
+
yield(wait_thr) if block_given?
|
71
69
|
|
72
|
-
|
73
|
-
|
70
|
+
out_thr.join
|
71
|
+
err_thr.join
|
74
72
|
exit_code = wait_thr.value.exitstatus
|
75
73
|
process_wait(pid)
|
76
74
|
end
|
@@ -105,29 +103,17 @@ module Frontkick
|
|
105
103
|
|
106
104
|
# private
|
107
105
|
|
108
|
-
def self.
|
106
|
+
def self.popen3_opts(opts)
|
109
107
|
opts.dup.tap {|o|
|
110
108
|
o.delete(:timeout_kill)
|
111
109
|
o.delete(:exclusive)
|
112
110
|
o.delete(:exclusive_blocking)
|
113
111
|
o.delete(:timeout)
|
114
|
-
o.delete(:
|
112
|
+
o.delete(:out)
|
113
|
+
o.delete(:err)
|
115
114
|
}
|
116
115
|
end
|
117
116
|
|
118
|
-
def self.trap_signal(pid)
|
119
|
-
trap :INT do
|
120
|
-
Process.kill(:TERM, pid)
|
121
|
-
process_wait(pid)
|
122
|
-
exit 130
|
123
|
-
end
|
124
|
-
trap :TERM do
|
125
|
-
Process.kill(:TERM, pid)
|
126
|
-
process_wait(pid)
|
127
|
-
exit 143
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
117
|
def self.process_wait(pid)
|
132
118
|
begin
|
133
119
|
pid, status = Process.waitpid2(pid) # wait child processes finish
|
data/lib/frontkick/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: frontkick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Naotoshi Seo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|