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.
@@ -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
- trap("INT") do
62
- stop!
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
@@ -1,3 +1,3 @@
1
1
  module Angael
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -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
- # Clean up
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.4
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-08 00:00:00 -07:00
13
+ date: 2011-06-14 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency