angael 0.0.4 → 0.0.5
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 +30 -6
- data/lib/angael/version.rb +1 -1
- data/spec/lib/angael/manager_spec.rb +46 -5
- metadata +2 -2
data/lib/angael/manager.rb
CHANGED
@@ -25,9 +25,14 @@ module Angael
|
|
25
25
|
# Logger::WARN
|
26
26
|
# Logger::INFO # Default
|
27
27
|
# Logger::DEBUG
|
28
|
+
# :restart_after => If set, 1 worker will be restarted after this number
|
29
|
+
# of seconds. If it is nil (the default), then workers will not get
|
30
|
+
# restarted for no reason. If your workers leak memory, this can help
|
31
|
+
# reduce the problem. A graceful restart is always attempted.
|
28
32
|
def initialize(worker_class, worker_count=1, worker_args=[], opts={})
|
29
33
|
@workers = []
|
30
34
|
worker_count.times { workers << worker_class.new(*worker_args) }
|
35
|
+
@restart_after = opts[:restart_after]
|
31
36
|
@logger = opts[:logger]
|
32
37
|
if @logger
|
33
38
|
@log_level = opts[:log_level] || begin
|
@@ -56,15 +61,24 @@ module Angael
|
|
56
61
|
end
|
57
62
|
end
|
58
63
|
end
|
64
|
+
trap("INT") do
|
65
|
+
stop!
|
66
|
+
end
|
67
|
+
trap("TERM") do
|
68
|
+
stop!
|
69
|
+
end
|
59
70
|
|
60
71
|
loop do
|
61
|
-
|
62
|
-
|
72
|
+
if @restart_after
|
73
|
+
# Periodically restart workers, 1 at a time.
|
74
|
+
sleep @restart_after
|
75
|
+
w = next_worker_to_restart
|
76
|
+
w.stop!
|
77
|
+
w.start!
|
78
|
+
else
|
79
|
+
# Don't restart workers if nothing is wrong.
|
80
|
+
sleep 1
|
63
81
|
end
|
64
|
-
trap("TERM") do
|
65
|
-
stop!
|
66
|
-
end
|
67
|
-
sleep 1
|
68
82
|
end
|
69
83
|
end
|
70
84
|
|
@@ -109,5 +123,15 @@ module Angael
|
|
109
123
|
[pid, nil] # It did exit, but we don't know the exit status.
|
110
124
|
end
|
111
125
|
end
|
126
|
+
|
127
|
+
def next_worker_to_restart
|
128
|
+
@worker_count ||= workers.size
|
129
|
+
@next_worker_to_restart_index ||= 0
|
130
|
+
@next_worker_to_restart_index += 1
|
131
|
+
@next_worker_to_restart_index %= @worker_count
|
132
|
+
|
133
|
+
workers[@next_worker_to_restart_index]
|
134
|
+
end
|
135
|
+
|
112
136
|
end
|
113
137
|
end
|
data/lib/angael/version.rb
CHANGED
@@ -39,13 +39,47 @@ describe Angael::Manager do
|
|
39
39
|
Process.wait(pid)
|
40
40
|
end
|
41
41
|
|
42
|
+
context "when :restart_after is set to 0.5" do
|
43
|
+
subject { Angael::Manager.new(Angael::TestSupport::SampleWorker, 3, [], :restart_after => 0.5) }
|
44
|
+
it "should restarts workers 1 at a time, at 1 second intervals" do
|
45
|
+
subject.workers.each do |w|
|
46
|
+
w.stub(:start!) # We don't actually need the workers to fork.
|
47
|
+
end
|
48
|
+
|
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
|
71
|
+
subject.start!
|
72
|
+
rescue SystemExit
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
clean_up_pid(pid)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
42
80
|
context "when it receives a SIGCHLD" do
|
43
81
|
after(:each) do
|
44
|
-
|
45
|
-
unless Process.wait2(@pid, Process::WNOHANG)
|
46
|
-
Process.kill('KILL', @pid) unless
|
47
|
-
Process.wait(@pid) rescue nil
|
48
|
-
end
|
82
|
+
clean_up_pid(@pid)
|
49
83
|
end
|
50
84
|
|
51
85
|
context "when worker was asked to stop" do
|
@@ -143,4 +177,11 @@ describe Angael::Manager do
|
|
143
177
|
end
|
144
178
|
end
|
145
179
|
end
|
180
|
+
|
181
|
+
def clean_up_pid(pid)
|
182
|
+
unless Process.wait2(pid, Process::WNOHANG)
|
183
|
+
Process.kill('KILL', pid) unless
|
184
|
+
Process.wait(pid) rescue nil
|
185
|
+
end
|
186
|
+
end
|
146
187
|
end
|
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.5
|
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-14 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|