xpool 0.10.0 → 0.10.1

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,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