angael 0.0.7 → 0.0.8
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.
- data/lib/angael/manager.rb +44 -30
- data/lib/angael/process_helper.rb +37 -0
- data/lib/angael/version.rb +1 -1
- data/lib/angael/worker.rb +41 -50
- data/spec/lib/angael/manager_spec.rb +41 -30
- data/spec/lib/angael/process_helper_spec.rb +72 -0
- data/spec/lib/angael/worker_spec.rb +60 -16
- metadata +4 -2
data/lib/angael/manager.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
require 'angael/process_helper'
|
1
2
|
module Angael
|
2
3
|
# A Manager has a number of of worker objects. Starting the Manager simply
|
3
4
|
# calls #start! on each worker, then it goes into an infinite loop, waiting
|
4
5
|
# for SIGINT or SIGTERM. When either of those is received, the manager will
|
5
|
-
# call #
|
6
|
+
# call #stop_with_wait on each Worker.
|
6
7
|
class Manager
|
8
|
+
include ProcessHelper
|
7
9
|
attr_reader :workers
|
8
10
|
|
9
11
|
# Creates a new manager.
|
10
12
|
#
|
11
13
|
# @worker_class [Class] The class to use for the workers. Must respond
|
12
|
-
# to #new, #start!, and #
|
14
|
+
# to #new, #start!, and #stop_with_wait
|
13
15
|
# @worker_count [Integer] The number of workers to manager. Default is 1.
|
14
16
|
# @worker_args [Array] An array of arguments that will be passed to
|
15
17
|
# worker_class.new. The arguments will be splatted
|
@@ -33,6 +35,8 @@ module Angael
|
|
33
35
|
@workers = []
|
34
36
|
worker_count.times { workers << worker_class.new(*worker_args) }
|
35
37
|
@restart_after = opts[:restart_after]
|
38
|
+
# TODO: Add a spec for this
|
39
|
+
raise ArgumentError, ':restart_after must be either an Integer greater than zero or nil' if @restart_after && (@restart_after.to_i != @restart_after || @restart_after == 0)
|
36
40
|
@logger = opts[:logger]
|
37
41
|
if @logger
|
38
42
|
@log_level = opts[:log_level] || begin
|
@@ -44,13 +48,13 @@ module Angael
|
|
44
48
|
|
45
49
|
|
46
50
|
# Starts workers by calling Worker#start! Loops forever waiting for SIGINT
|
47
|
-
# or SIGTERM, at which time it calls Worker#
|
51
|
+
# or SIGTERM, at which time it calls Worker#stop_with_wait on each worker.
|
48
52
|
def start!
|
49
53
|
workers.each { |w| w.start! }
|
50
54
|
|
51
55
|
trap("CHLD") do
|
52
56
|
workers.each do |w|
|
53
|
-
result =
|
57
|
+
result = exit_status(w.pid)
|
54
58
|
#print w.pid.to_s
|
55
59
|
#print "\t"
|
56
60
|
#p result
|
@@ -62,23 +66,40 @@ module Angael
|
|
62
66
|
end
|
63
67
|
end
|
64
68
|
trap("INT") do
|
65
|
-
|
69
|
+
log("SIGINT Received")
|
70
|
+
@interrupted = true
|
66
71
|
end
|
67
72
|
trap("TERM") do
|
68
|
-
|
73
|
+
log("SIGTERM Received")
|
74
|
+
@interrupted = true
|
69
75
|
end
|
70
76
|
|
71
77
|
if @restart_after
|
78
|
+
restart_after_counter = @restart_after
|
72
79
|
loop do
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
80
|
+
stop! if @interrupted
|
81
|
+
|
82
|
+
# This ensures we are checking @interrupted every 1 second, but we
|
83
|
+
# can set @restart_after to something greater than zero.
|
84
|
+
if restart_after_counter > 0
|
85
|
+
sleep 1
|
86
|
+
restart_after_counter -= 1
|
87
|
+
else
|
88
|
+
# Periodically restart workers, 1 at a time.
|
89
|
+
log("Sleeping for #@restart_after seconds")
|
90
|
+
w = next_worker_to_restart
|
91
|
+
log("Time to restart a worker: Calling #stop_with_wait for worker #{w.inspect}")
|
92
|
+
w.stop_with_wait
|
93
|
+
log("Worker has been stopped: #{w.inspect}")
|
94
|
+
w.start!
|
95
|
+
log("Worker has been restarted: #{w.inspect}")
|
96
|
+
w = nil
|
97
|
+
restart_after_counter = @restart_after
|
98
|
+
end
|
78
99
|
end
|
79
100
|
else
|
80
101
|
loop do
|
81
|
-
|
102
|
+
stop! if @interrupted
|
82
103
|
sleep 1
|
83
104
|
end
|
84
105
|
end
|
@@ -91,11 +112,18 @@ module Angael
|
|
91
112
|
#########
|
92
113
|
|
93
114
|
def stop!
|
94
|
-
log("
|
115
|
+
log("Attempting to gracefully stopping worker manager")
|
116
|
+
# Tell each worker to stop, without waiting to see if it worked.
|
117
|
+
workers.each { |w|
|
118
|
+
log("Calling #stop_without_wait for worker #{w.inspect}")
|
119
|
+
w.stop_without_wait
|
120
|
+
log("Finished call to #stop_without_wait for worker #{w.inspect}")
|
121
|
+
}
|
122
|
+
# Wait for each worker to stop, one at a time.
|
95
123
|
workers.each { |w|
|
96
|
-
log("Calling #
|
97
|
-
w.
|
98
|
-
log("Finished call to #
|
124
|
+
log("Calling #stop_with_wait for worker #{w.inspect}")
|
125
|
+
w.stop_with_wait
|
126
|
+
log("Finished call to #stop_with_wait for worker #{w.inspect}")
|
99
127
|
}
|
100
128
|
exit 0
|
101
129
|
end
|
@@ -104,20 +132,6 @@ module Angael
|
|
104
132
|
@logger.add(@log_level, "#{Time.now.utc} - #{self.class} (pid #{$$}): #{msg}") if @logger
|
105
133
|
end
|
106
134
|
|
107
|
-
# Returns immediately. If the process is still running, it returns nil.
|
108
|
-
# If the process is a zombie, it returns an array with the pid as the
|
109
|
-
# first element and a Process::Status object as the 2nd element, i.e.
|
110
|
-
# it returns the same thing as Process.wait2. If the process does not
|
111
|
-
# exist (i.e. it is completely gone) then it returns an array with the
|
112
|
-
# pid as the first element and nil as the 2nd element (because there
|
113
|
-
# is no Process::Status object to return).
|
114
|
-
def wait(pid)
|
115
|
-
begin
|
116
|
-
Process.wait2(pid, Process::WNOHANG)
|
117
|
-
rescue Errno::ECHILD
|
118
|
-
[pid, nil] # It did exit, but we don't know the exit status.
|
119
|
-
end
|
120
|
-
end
|
121
135
|
|
122
136
|
def next_worker_to_restart
|
123
137
|
@worker_count ||= workers.size
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Angael
|
2
|
+
module ProcessHelper
|
3
|
+
# Returns immediately. If the process is still running, it returns nil.
|
4
|
+
# If the process is a zombie, it returns an array with the pid as the
|
5
|
+
# first element and a Process::Status object as the 2nd element, i.e.
|
6
|
+
# it returns the same thing as Process.wait2. If the process does not
|
7
|
+
# exist (i.e. it is completely gone) or it is not accessible to the
|
8
|
+
# current process (i.e. an Errno::EPERM error is raised), then this method
|
9
|
+
# returns an array with the pid as the first element and nil as the 2nd
|
10
|
+
# element (because there is no Process::Status object to return).
|
11
|
+
# If the argument is nil, then it returns [nil, nil] because there can't be
|
12
|
+
# a process running with the pid nil.
|
13
|
+
def exit_status(pid)
|
14
|
+
return [nil, nil] if pid.nil?
|
15
|
+
|
16
|
+
# Sometimes wait2 returns nil even when the process has exited. This
|
17
|
+
# raises an Errno::ESRCH error in that case.
|
18
|
+
raise "Unexpected return value from Process.kill(0, pid)" unless Process.kill(0, pid) == 1
|
19
|
+
|
20
|
+
Process.wait2(pid, Process::WNOHANG)
|
21
|
+
rescue Errno::ECHILD, Errno::ESRCH, Errno::EPERM
|
22
|
+
# There is no longer any record of this PID.
|
23
|
+
# It did exit, but we don't know the exit status.
|
24
|
+
[pid, nil]
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Will return nil instead of raising Errno::ESRCH when the process does
|
29
|
+
# not exists.
|
30
|
+
# TODO: Add explicit tests for this.
|
31
|
+
def send_signal(signal, pid)
|
32
|
+
Process.kill(signal, pid)
|
33
|
+
rescue Errno::ESRCH
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/angael/version.rb
CHANGED
data/lib/angael/worker.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'angael/process_helper'
|
2
2
|
module Angael
|
3
3
|
# Usage
|
4
4
|
# include Angael::Worker
|
@@ -17,6 +17,7 @@ module Angael
|
|
17
17
|
# it is sent SIGINT. If you don't define this method, it waits
|
18
18
|
# 60 seconds.
|
19
19
|
module Worker
|
20
|
+
include ProcessHelper
|
20
21
|
class ChildProcessNotStoppedError < StandardError; end
|
21
22
|
|
22
23
|
attr_reader :pid
|
@@ -64,9 +65,13 @@ module Angael
|
|
64
65
|
start!
|
65
66
|
end
|
66
67
|
|
67
|
-
|
68
|
+
# Returns true if SIGINT was sent to the child process, even if the child
|
69
|
+
# process does not exists.
|
70
|
+
# Returns false if started? is true.
|
71
|
+
# Sets stopping? to false.
|
72
|
+
def stop_without_wait
|
68
73
|
unless started?
|
69
|
-
__log("
|
74
|
+
__log("Tried to stop worker with PID #{pid} but it is not started")
|
70
75
|
return false
|
71
76
|
end
|
72
77
|
|
@@ -74,28 +79,38 @@ module Angael
|
|
74
79
|
# stopped the child process.
|
75
80
|
@stopping = true
|
76
81
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
82
|
+
__log("Sending SIGINT to child process with pid #{pid}.")
|
83
|
+
send_signal('INT', pid)
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
87
|
+
# Keeps sending SIGINT until the child process exits. If #timeout seconds
|
88
|
+
# pass, then it sends 1 SIGKILL. If that also fails, it raises ChildProcessNotStoppedError.
|
89
|
+
def stop_with_wait
|
90
|
+
return false unless stop_without_wait
|
91
|
+
|
92
|
+
__log("Waiting for child process with pid #{pid} to stop.")
|
93
|
+
|
94
|
+
counter = 0
|
95
|
+
|
96
|
+
while pid_running? && counter < timeout
|
97
|
+
sleep 1
|
98
|
+
counter += 1
|
99
|
+
__log("Sending SIGINT to child process with pid #{pid}. Attempt Count: #{counter}.")
|
100
|
+
send_signal('INT', pid)
|
101
|
+
end
|
102
|
+
|
103
|
+
if pid_running?
|
104
|
+
__log("Child process with pid #{pid} did not stop within #{timeout} seconds of SIGINT. Sending SIGKILL to child process.")
|
105
|
+
send_signal('KILL', pid)
|
106
|
+
sleep 1
|
107
|
+
end
|
108
|
+
|
109
|
+
if pid_running?
|
110
|
+
# SIGKILL didn't work.
|
111
|
+
msg = "Unable to kill child process with PID: #{pid}"
|
112
|
+
__log(msg)
|
113
|
+
raise ChildProcessNotStoppedError, msg
|
99
114
|
end
|
100
115
|
end
|
101
116
|
|
@@ -132,34 +147,10 @@ module Angael
|
|
132
147
|
end
|
133
148
|
|
134
149
|
|
135
|
-
# Note: if the pid is running, but this process doesn't have permissions to
|
136
|
-
# access it, then this will return false.
|
137
150
|
def pid_running?
|
138
|
-
|
139
|
-
Process.kill(0, pid) == 1
|
140
|
-
rescue Errno::ESRCH, Errno::EPERM
|
141
|
-
false
|
142
|
-
end
|
151
|
+
!exit_status(pid)
|
143
152
|
end
|
144
153
|
|
145
|
-
# Will just return if the child process is not running.
|
146
|
-
def wait_for_child(opts={})
|
147
|
-
begin
|
148
|
-
__log("Waiting for child with pid #{pid}.")
|
149
|
-
if opts[:dont_block]
|
150
|
-
# When this is called as the result of a SIGCHLD
|
151
|
-
# we need to pass in Process::WNOHANG as the 2nd argument, otherwise when
|
152
|
-
# there are multiple workers, some workers will trap SIGCHLD when other
|
153
|
-
# workers' child processes die. Without this argument, those workers will
|
154
|
-
# hang forever, which also hangs the worker manager.
|
155
|
-
Process.wait(pid, Process::WNOHANG)
|
156
|
-
else
|
157
|
-
Process.wait(pid)
|
158
|
-
end
|
159
|
-
rescue Errno::ECHILD
|
160
|
-
# The child process has already been reaped.
|
161
|
-
end
|
162
|
-
end
|
163
154
|
|
164
155
|
# This is the standard/default way of doing it. Overwrite this if you want
|
165
156
|
# to wrap it in an exception handler, for example.
|
@@ -40,40 +40,33 @@ describe Angael::Manager do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
context "when :restart_after is set to 0.5" do
|
43
|
-
|
43
|
+
after do
|
44
|
+
clean_up_pid(@pid)
|
45
|
+
end
|
46
|
+
|
47
|
+
subject { Angael::Manager.new(Angael::TestSupport::SampleWorker, 3, [], :restart_after => 1) }
|
48
|
+
|
44
49
|
it "should restart workers 1 at a time, at 1 second intervals" do
|
45
50
|
subject.workers.each do |w|
|
46
|
-
|
51
|
+
# This isn't used for restarts.
|
52
|
+
w.stub(:stop_without_wait)
|
47
53
|
end
|
48
54
|
|
49
|
-
subject.workers[0].
|
50
|
-
subject.workers[1].
|
51
|
-
subject.workers[2].
|
52
|
-
|
53
|
-
subject.workers[0].
|
54
|
-
subject.workers[1].
|
55
|
-
subject.workers[2].
|
56
|
-
|
57
|
-
|
58
|
-
# As an alternative to should_receive_in_child_process, we
|
59
|
-
# fork a process which will send SIGINT to this current process.
|
60
|
-
# Then we start the Manager in this process and wait for it to
|
61
|
-
# get the SIGINT. Finally we rescue SystemExit so that this
|
62
|
-
# process doesn't exit with the Manager stops.
|
63
|
-
# TODO: Be consistent in my use of this technique vs. should_receive_in_child_process.
|
64
|
-
current_pid = $$
|
65
|
-
pid = Process.fork do
|
66
|
-
sleep 0.6 # Add a 0.1 second buffer to the value of :restart_after to give the process a chance to start.
|
67
|
-
Process.kill('INT', current_pid)
|
68
|
-
exit 0
|
69
|
-
end
|
70
|
-
begin
|
55
|
+
subject.workers[0].should_receive_in_child_process(:stop_with_wait).exactly(1).times
|
56
|
+
subject.workers[1].should_receive_in_child_process(:stop_with_wait).exactly(2).times # This is the worker that got restarted.
|
57
|
+
subject.workers[2].should_receive_in_child_process(:stop_with_wait).exactly(1).times
|
58
|
+
|
59
|
+
subject.workers[0].should_receive_in_child_process(:start!).exactly(1).times
|
60
|
+
subject.workers[1].should_receive_in_child_process(:start!).exactly(2).times # This is the worker that got restarted.
|
61
|
+
subject.workers[2].should_receive_in_child_process(:start!).exactly(1).times
|
62
|
+
|
63
|
+
@pid = Process.fork do
|
71
64
|
subject.start!
|
72
|
-
rescue SystemExit
|
73
|
-
nil
|
74
65
|
end
|
75
66
|
|
76
|
-
|
67
|
+
sleep 1.1 # Add a 0.1 second buffer to the value of :restart_after to give the process a chance to start.
|
68
|
+
Process.kill('INT', @pid)
|
69
|
+
|
77
70
|
end
|
78
71
|
end
|
79
72
|
|
@@ -94,7 +87,7 @@ describe Angael::Manager do
|
|
94
87
|
end
|
95
88
|
|
96
89
|
sleep 0.1 # Give the process a chance to start.
|
97
|
-
# This sends
|
90
|
+
# This sends stop_with_wait to all the workers.
|
98
91
|
Process.kill('INT', @pid)
|
99
92
|
sleep 0.1 # Give the TempFile a chance to flush
|
100
93
|
end
|
@@ -157,11 +150,29 @@ describe Angael::Manager do
|
|
157
150
|
|
158
151
|
%w(INT TERM).each do |sig|
|
159
152
|
context "when it receives a SIG#{sig}" do
|
160
|
-
it "should call #
|
153
|
+
it "should call #stop_without_wait on each Worker" do
|
154
|
+
subject.workers.each do |w|
|
155
|
+
w.stub(:start!) # We don't care about the sub-process, so don't start it.
|
156
|
+
|
157
|
+
w.should_receive_in_child_process(:stop_without_wait).at_least(1).times
|
158
|
+
end
|
159
|
+
|
160
|
+
pid = Process.fork do
|
161
|
+
subject.start!
|
162
|
+
end
|
163
|
+
sleep 0.1 # Give the process a chance to start.
|
164
|
+
Process.kill(sig, pid)
|
165
|
+
sleep 0.1 # Give the TempFile a chance to flush
|
166
|
+
|
167
|
+
# Clean up
|
168
|
+
Process.wait(pid)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should call #stop_with_wait on each Worker" do
|
161
172
|
subject.workers.each do |w|
|
162
173
|
w.stub(:start!) # We don't care about the sub-process, so don't start it.
|
163
174
|
|
164
|
-
w.should_receive_in_child_process(:
|
175
|
+
w.should_receive_in_child_process(:stop_with_wait)
|
165
176
|
end
|
166
177
|
|
167
178
|
pid = Process.fork do
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Angael::ProcessHelper do
|
4
|
+
include Angael::ProcessHelper
|
5
|
+
|
6
|
+
describe "exit_status" do
|
7
|
+
context "when passed the argument nil" do
|
8
|
+
it "should return an array of [nil, nil]" do
|
9
|
+
exit_status(nil).should == [nil, nil]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when Process.kill raises Errno::ESRCH" do
|
14
|
+
before { Process.stub(:kill) { raise Errno::ESRCH } }
|
15
|
+
it "should return an array of [pid, nil]" do
|
16
|
+
exit_status(123456).should == [123456, nil]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when Process.kill raises Errno::EPERM" do
|
21
|
+
before { Process.stub(:kill) { raise Errno::EPERM } }
|
22
|
+
it "should return an array of [pid, nil]" do
|
23
|
+
exit_status(123456).should == [123456, nil]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when Process.kill return 1" do
|
28
|
+
before { Process.stub(:kill).and_return(1) }
|
29
|
+
|
30
|
+
context "when Process.wait2 raises Errno::ECHILD" do
|
31
|
+
before { Process.stub(:wait2) { raise Errno::ECHILD } }
|
32
|
+
it "should return an array of [pid, nil]" do
|
33
|
+
exit_status(123456).should == [123456, nil]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when Process.wait2 returns nil" do
|
38
|
+
before { Process.stub(:wait2).and_return(nil) }
|
39
|
+
it "should return nil" do
|
40
|
+
exit_status(123456).should be_nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when Process.wait2 returns an array of [pid, exitstatus]" do
|
45
|
+
before do
|
46
|
+
@exitstatus = mock(Process::Status)
|
47
|
+
Process.stub(:wait2).and_return([123456, @exitstatus])
|
48
|
+
end
|
49
|
+
it "should return an array of [pid, exitstatus]" do
|
50
|
+
exit_status(123456).should == [123456, @exitstatus]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
describe "send_signal" do
|
58
|
+
it "should call kill" do
|
59
|
+
pid = 123456
|
60
|
+
sig = 'INT'
|
61
|
+
Process.should_receive(:kill).with(sig, pid)
|
62
|
+
send_signal(sig, pid)
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when Process.kill raises Errno::ESRCH" do
|
66
|
+
it "should return nil" do
|
67
|
+
Process.stub(:kill) { raise Errno::ESRCH }
|
68
|
+
send_signal('INT', 123456).should be_nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -7,7 +7,7 @@ describe Angael::Worker do
|
|
7
7
|
|
8
8
|
describe "#start!" do
|
9
9
|
before { subject.stub(:work => nil) }
|
10
|
-
after { subject.
|
10
|
+
after { subject.stop_with_wait if subject.started? }
|
11
11
|
|
12
12
|
it "should set #pid" do
|
13
13
|
subject.pid.should be_nil
|
@@ -85,24 +85,68 @@ describe Angael::Worker do
|
|
85
85
|
|
86
86
|
|
87
87
|
|
88
|
-
describe "#
|
88
|
+
describe "#stop_without_wait" do
|
89
89
|
before { subject.stub(:work => nil) }
|
90
|
-
after { subject.
|
90
|
+
after { subject.stop_with_wait }
|
91
91
|
|
92
92
|
context "when stopped" do
|
93
93
|
it "should return false" do
|
94
94
|
subject.should_not be_started
|
95
|
-
subject.
|
95
|
+
subject.stop_without_wait.should be_false
|
96
96
|
end
|
97
97
|
|
98
98
|
it "should not be stopping" do
|
99
|
-
subject.
|
99
|
+
subject.stop_without_wait
|
100
100
|
subject.should_not be_stopping
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should not send a SIGINT to the child process" do
|
104
104
|
should_not_receive_and_run(Process, :kill, 'INT', subject.pid)
|
105
|
-
subject.
|
105
|
+
subject.stop_without_wait
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should return false" do
|
109
|
+
subject.stop_without_wait.should be_false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "when started" do
|
114
|
+
before { subject.start! }
|
115
|
+
it "should send a SIGINT to the child process" do
|
116
|
+
should_receive_and_run(Process, :kill, 'INT', subject.pid)
|
117
|
+
subject.stop_without_wait
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should be stopping" do
|
121
|
+
subject.stop_without_wait
|
122
|
+
subject.should be_stopping
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should return true" do
|
126
|
+
subject.stop_without_wait.should be_true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
describe "#stop_with_wait" do
|
133
|
+
before { subject.stub(:work => nil) }
|
134
|
+
after { subject.stop_with_wait }
|
135
|
+
|
136
|
+
context "when stopped" do
|
137
|
+
it "should return false" do
|
138
|
+
subject.should_not be_started
|
139
|
+
subject.stop_with_wait.should be_false
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should not be stopping" do
|
143
|
+
subject.stop_with_wait
|
144
|
+
subject.should_not be_stopping
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should not send a SIGINT to the child process" do
|
148
|
+
should_not_receive_and_run(Process, :kill, 'INT', subject.pid)
|
149
|
+
subject.stop_with_wait
|
106
150
|
end
|
107
151
|
end
|
108
152
|
|
@@ -110,12 +154,12 @@ describe Angael::Worker do
|
|
110
154
|
it "should send a SIGINT to the child process" do
|
111
155
|
subject.start!
|
112
156
|
should_receive_and_run(Process, :kill, 'INT', subject.pid)
|
113
|
-
subject.
|
157
|
+
subject.stop_with_wait
|
114
158
|
end
|
115
159
|
|
116
160
|
it "should be stopping" do
|
117
161
|
subject.start!
|
118
|
-
subject.
|
162
|
+
subject.stop_with_wait
|
119
163
|
subject.should be_stopping
|
120
164
|
end
|
121
165
|
|
@@ -130,23 +174,23 @@ describe Angael::Worker do
|
|
130
174
|
subject.start!
|
131
175
|
end
|
132
176
|
it "should be stopped" do
|
133
|
-
subject.
|
177
|
+
subject.stop_with_wait
|
134
178
|
subject.should be_stopped
|
135
179
|
end
|
136
180
|
|
137
181
|
it "should not have a child process with the pid #pid" do
|
138
|
-
subject.
|
182
|
+
subject.stop_with_wait
|
139
183
|
pid_running?(subject.pid).should be_false
|
140
184
|
end
|
141
185
|
|
142
186
|
it "should not send a SIGKILL to the child process" do
|
143
187
|
should_not_receive_and_run(Process, :kill, 'KILL', subject.pid)
|
144
|
-
subject.
|
188
|
+
subject.stop_with_wait
|
145
189
|
end
|
146
190
|
|
147
191
|
it "should have the (now dead) child process' PID as #pid" do
|
148
192
|
pid = subject.pid
|
149
|
-
subject.
|
193
|
+
subject.stop_with_wait
|
150
194
|
subject.pid.should == pid
|
151
195
|
end
|
152
196
|
end
|
@@ -164,18 +208,18 @@ describe Angael::Worker do
|
|
164
208
|
end
|
165
209
|
|
166
210
|
it "should be stopped" do
|
167
|
-
subject.
|
211
|
+
subject.stop_with_wait
|
168
212
|
subject.should be_stopped
|
169
213
|
end
|
170
214
|
|
171
215
|
it "should not have a child process with the pid #pid" do
|
172
|
-
subject.
|
216
|
+
subject.stop_with_wait
|
173
217
|
pid_running?(subject.pid).should be_false
|
174
218
|
end
|
175
219
|
|
176
220
|
it "should send a SIGKILL to the child process" do
|
177
221
|
should_receive_and_run(Process, :kill, 'KILL', subject.pid)
|
178
|
-
subject.
|
222
|
+
subject.stop_with_wait
|
179
223
|
end
|
180
224
|
|
181
225
|
context "child process does not die after receiving SIGKILL" do
|
@@ -204,7 +248,7 @@ describe Angael::Worker do
|
|
204
248
|
it "should raise an error with the child process' pid in the message" do
|
205
249
|
pid_running?(subject.pid).should be_true
|
206
250
|
lambda do
|
207
|
-
subject.
|
251
|
+
subject.stop_with_wait
|
208
252
|
end.should raise_error(Angael::Worker::ChildProcessNotStoppedError, /#{subject.pid}/)
|
209
253
|
|
210
254
|
# Confirm the PID is still running
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: angael
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.8
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Paul Cortens
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-06-
|
13
|
+
date: 2011-06-20 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -51,9 +51,11 @@ files:
|
|
51
51
|
- angael.gemspec
|
52
52
|
- lib/angael.rb
|
53
53
|
- lib/angael/manager.rb
|
54
|
+
- lib/angael/process_helper.rb
|
54
55
|
- lib/angael/version.rb
|
55
56
|
- lib/angael/worker.rb
|
56
57
|
- spec/lib/angael/manager_spec.rb
|
58
|
+
- spec/lib/angael/process_helper_spec.rb
|
57
59
|
- spec/lib/angael/worker_spec.rb
|
58
60
|
- spec/spec_helper.rb
|
59
61
|
- spec/support/io_helpers.rb
|