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.
@@ -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 #stop! on each Worker.
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 #stop!
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#stop! on each 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 = wait(w.pid)
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
- stop!
69
+ log("SIGINT Received")
70
+ @interrupted = true
66
71
  end
67
72
  trap("TERM") do
68
- stop!
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
- # Periodically restart workers, 1 at a time.
74
- sleep @restart_after
75
- w = next_worker_to_restart
76
- w.stop!
77
- w.start!
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
- # Don't restart workers if nothing is wrong.
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("SIGINT Received")
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 #stop! for worker #{w.inspect}")
97
- w.stop!
98
- log("Finished call to #stop! for worker #{w.inspect}")
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
@@ -1,3 +1,3 @@
1
1
  module Angael
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
data/lib/angael/worker.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'timeout'
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
- def stop!
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("Called stop for worker with PID #{pid} but it is not started")
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
- begin
78
- __log("Sending SIGINT to child process with pid #{pid}.")
79
- Timeout::timeout(timeout) do
80
- Process.kill('INT', pid)
81
- wait_for_child
82
- end
83
- rescue Timeout::Error
84
- begin
85
- __log("Child process with pid #{pid} did not stop within #{timeout} seconds of SIGINT. Sending SIGKILL to child process.")
86
- # This only leaves 1 second for the SIGKILL to take effect. I don't
87
- # know if that is enough time (or maybe too much time).
88
- Timeout::timeout(1) do
89
- Process.kill('KILL', pid)
90
- wait_for_child
91
- end
92
- rescue Timeout::Error
93
- if pid_running?
94
- msg = "Unable to kill child process with PID: #{pid}"
95
- __log(msg)
96
- raise ChildProcessNotStoppedError, msg
97
- end
98
- end
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
- begin
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
- subject { Angael::Manager.new(Angael::TestSupport::SampleWorker, 3, [], :restart_after => 0.5) }
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
- w.stub(:start!) # We don't actually need the workers to fork.
51
+ # This isn't used for restarts.
52
+ w.stub(:stop_without_wait)
47
53
  end
48
54
 
49
- subject.workers[0].should_receive(:stop!).exactly(1).times
50
- subject.workers[1].should_receive(:stop!).exactly(2).times # This is the worker that got restarted.
51
- subject.workers[2].should_receive(:stop!).exactly(1).times
52
-
53
- subject.workers[0].should_receive(:start!).exactly(1).times
54
- subject.workers[1].should_receive(:start!).exactly(2).times # This is the worker that got restarted.
55
- subject.workers[2].should_receive(:start!).exactly(1).times
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
- clean_up_pid(pid)
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 stop! to all the workers.
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 #stop! on each Worker" do
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(:stop!)
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.stop! if subject.started? }
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 "#stop!" do
88
+ describe "#stop_without_wait" do
89
89
  before { subject.stub(:work => nil) }
90
- after { subject.stop! }
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.stop!.should be_false
95
+ subject.stop_without_wait.should be_false
96
96
  end
97
97
 
98
98
  it "should not be stopping" do
99
- subject.stop!
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.stop!
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.stop!
157
+ subject.stop_with_wait
114
158
  end
115
159
 
116
160
  it "should be stopping" do
117
161
  subject.start!
118
- subject.stop!
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.stop!
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.stop!
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.stop!
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.stop!
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.stop!
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.stop!
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.stop!
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.stop!
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.7
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-14 00:00:00 -07:00
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