frontkick 0.5.0 → 0.5.1

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: c1ec1035f37f85a6c2df0efac9c9a2bf94f924aa
4
- data.tar.gz: f86e5798517525996d28f8e9ea37752864771b50
3
+ metadata.gz: 21315e4ecfde359617b02081d2252b558e576acd
4
+ data.tar.gz: 158fd87c5c96234c08ac944259b734d580f4a7bf
5
5
  SHA512:
6
- metadata.gz: 15f13d612326c77c06c274c0a21be7d80c5da51018a1060f8092ead9170387079cf99bc77447acc7aab34dd51a125b72cd0bf3dc46118aa7f682e6c54cf3c6f3
7
- data.tar.gz: 13eb2a6ddc5fd04aba31e499428c17ba982e5a0ac6c80a80f6c668bf8cfb3cacdf7a1b056e98bb5d1488b1b0d527b08435680f252331bfc806dcc2b4fa97b1ca
6
+ metadata.gz: cca5e9b8043cf202446b3592d3370f17b3d5bdbe490df40e0b82f90b852154e2c44e157e74a901ab26427ffcd07bf82ea43e9ecfca16a2840c3486d4e210252f
7
+ data.tar.gz: 0cba11a2c72e2be354087dfb9d79c4df17ee2b737c6ad1c19457ce6dc78488a53d43dfa3b7804ec9a3c74c04633b766177ec59e64877497a07a5f2cd1640a3d4
@@ -1,3 +1,9 @@
1
+ # 0.5.1 (2016/01/23)
2
+
3
+ Changes:
4
+
5
+ - Drop :kill_child option, instead, support pid block
6
+
1
7
  # 0.5.0 (2016/01/22)
2
8
 
3
9
  Enhancements:
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
- ### Kill Child Option
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
@@ -1,5 +1,51 @@
1
1
  require 'frontkick'
2
2
 
3
- puts Process.pid
4
- result = Frontkick.exec(["sleep 3000"], :kill_child => true)
5
- puts result.stdout
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
@@ -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
@@ -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
- spawn_opts = self.spawn_opts(opts)
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, spawn_opts)
49
- out_thread = Thread.new {
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
- err_thread = Thread.new {
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 opts[:kill_child]
69
- trap_signal(pid)
70
- end
68
+ yield(wait_thr) if block_given?
71
69
 
72
- out_thread.join
73
- err_thread.join
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.spawn_opts(opts)
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(:kill_child)
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
@@ -1,3 +1,3 @@
1
1
  module Frontkick
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
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.0
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-22 00:00:00.000000000 Z
11
+ date: 2016-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake