xpool 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,23 @@
1
+ == HEAD
2
+ - no longer log from trap(…) block.
3
+ the logger cannot log from within a trap block on Ruby2, so I've removed
4
+ logging when a subprocess gets a request to shutdown.
5
+
6
+ - call 'setup' on unit of work if defined.
7
+ 'setup', if defined by a unit of work, is called just before a unit of work
8
+ is executed for the first time… useful if you need to create an environment
9
+ for the subprocess to operate in.
10
+
11
+ - resize & resize! no longer accepts a Range.
12
+ deprecated in the last release, support for a Range to either resize or
13
+ resize! is completely removed in this release. Please use a Fixnum instead.
14
+
15
+ == v0.10.1
16
+ - Restarted subprocesses inherit the message queue of their predecessor.
17
+ when a failed subprocess is restarted its message queue is inherited by its
18
+ replacement. Any messages it had waiting will be processed by the replacement
19
+ process.
20
+
1
21
  == v0.10.0
2
22
  - default to two subprocesses if CPU core count cannot be guessed.
3
23
  Which is change from the old default of five.
@@ -4,6 +4,7 @@ class XPool::Process
4
4
  # Returns an instance of XPool::Process
5
5
  #
6
6
  def initialize
7
+ reset
7
8
  @id = spawn
8
9
  end
9
10
 
@@ -115,25 +116,32 @@ class XPool::Process
115
116
  @states[:backtrace]
116
117
  end
117
118
 
119
+ #
120
+ # Restart the process. The current process shuts down(gracefully) and a new
121
+ # process replaces it. If the current process has failed the new process will
122
+ # inherit its message queue.
118
123
  #
119
124
  # @return [Fixnum]
120
125
  # Returns the process ID of the new process.
121
126
  #
122
127
  def restart
123
- shutdown
128
+ _shutdown 'SIGUSR1', false
129
+ reset(false)
124
130
  @id = spawn
125
131
  end
126
132
 
127
133
  private
128
- def _shutdown(sig)
134
+ def _shutdown(sig, close_channels=true)
129
135
  Process.kill sig, @id
130
136
  Process.wait @id
131
137
  rescue Errno::ECHILD, Errno::ESRCH
132
138
  ensure
133
139
  @states = {dead: true} unless failed?
134
140
  @shutdown = true
135
- @channel.close
136
- @s_channel.close
141
+ if close_channels
142
+ @channel.close
143
+ @s_channel.close
144
+ end
137
145
  end
138
146
 
139
147
  def synchronize!
@@ -144,16 +152,17 @@ private
144
152
  @states
145
153
  end
146
154
 
147
- def reset
148
- @channel = IChannel.new Marshal
149
- @s_channel = IChannel.new Marshal
155
+ def reset(new_channels = true)
156
+ if new_channels
157
+ @channel = IChannel.new Marshal
158
+ @s_channel = IChannel.new Marshal
159
+ end
150
160
  @shutdown = false
151
161
  @states = {}
152
162
  @frequency = 0
153
163
  end
154
164
 
155
165
  def spawn
156
- reset
157
166
  fork do
158
167
  trap :SIGUSR1 do
159
168
  XPool.log "#{::Process.pid} got request to shutdown."
@@ -172,8 +181,8 @@ private
172
181
  end
173
182
  sleep 0.05
174
183
  rescue Exception => e
175
- XPool.log "#{::Process.pid} has failed."
176
184
  @s_channel.put failed: true, dead: true, backtrace: e.backtrace
185
+ XPool.log "Process with ID '#{@id}' has failed."
177
186
  raise e
178
187
  ensure
179
188
  if @shutdown_requested && !@channel.readable?
@@ -1,3 +1,3 @@
1
1
  class XPool
2
- VERSION = "0.10.0"
2
+ VERSION = "0.10.1"
3
3
  end
@@ -13,9 +13,21 @@ class IOWriter
13
13
  end
14
14
 
15
15
  def wrote_to_disk?
16
- return @wrote_to_disk if defined?(@wrote_to_disk)
17
- @wrote_to_disk = File.read(@path) == 'true'
18
- FileUtils.rm_rf @path
19
- @wrote_to_disk
16
+ if File.exist? @path
17
+ val = File.read(@path)
18
+ FileUtils.rm_rf @path
19
+ val == 'true'
20
+ end
21
+ end
22
+ end
23
+
24
+ class IOSetupWriter < IOWriter
25
+ def setup
26
+ File.open @path, 'w' do |f|
27
+ f.write 'true'
28
+ end
29
+ end
30
+
31
+ def run
20
32
  end
21
33
  end
@@ -1,5 +1,10 @@
1
1
  class Raiser
2
+ def initialize(seconds = 0)
3
+ @seconds = seconds
4
+ end
5
+
2
6
  def run
7
+ sleep @seconds
3
8
  raise RuntimeError, "", %w(42)
4
9
  end
5
10
  end
@@ -8,6 +8,16 @@ class XPoolProcessTest < Test::Unit::TestCase
8
8
  @process.shutdown!
9
9
  end
10
10
 
11
+ def test_resume_process_on_failed_process_queue
12
+ @process.schedule Raiser.new(0.1)
13
+ io_writers = Array.new(5) { IOWriter.new }
14
+ io_writers.each { |writer| @process.schedule writer }
15
+ until @process.failed?; sleep 0.1; end
16
+ @process.restart
17
+ sleep 0.5
18
+ io_writers.each { |io_writer| assert io_writer.wrote_to_disk? }
19
+ end
20
+
11
21
  def test_busy_method
12
22
  @process.schedule Sleeper.new(0.5)
13
23
  sleep 0.1
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xpool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-27 00:00:00.000000000 Z
12
+ date: 2013-04-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ichannel
@@ -70,7 +70,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
70
70
  version: '0'
71
71
  segments:
72
72
  - 0
73
- hash: -4088700810187342227
73
+ hash: -3457064609731373945
74
74
  required_rubygems_version: !ruby/object:Gem::Requirement
75
75
  none: false
76
76
  requirements:
@@ -79,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
79
  version: '0'
80
80
  segments:
81
81
  - 0
82
- hash: -4088700810187342227
82
+ hash: -3457064609731373945
83
83
  requirements: []
84
84
  rubyforge_project:
85
85
  rubygems_version: 1.8.23