Class: Mutineer::WorkerPool
- Inherits:
-
Object
- Object
- Mutineer::WorkerPool
- Defined in:
- lib/mutineer/worker_pool.rb
Overview
Fixed-size fork pool. run forks up to size children at once; each child
runs the block on one work item, marshals its Result to a private pipe, and
exits. The parent drains pipes with IO.select and reaps each finished child
by known pid (never wait2(-1), which would steal the host suite's children),
opening exactly one slot per reap, then refills. Results are returned in the
SAME ORDER as items regardless of finish order, so verdicts are identical
to a serial run and downstream output is stable.
The block is run inside the child via yield(*items[i]); whatever it
returns (a Result) is the marshaled payload. Per-mutant timeout is handled
one level down by Isolation. The pool adds no separate wall clock.
Instance Method Summary collapse
-
#initialize(size) ⇒ WorkerPool
constructor
Builds a pool.
-
#run(items, stop_when: nil) {|item| ... } ⇒ Array<Mutineer::Result>
Runs the work items through the pool.
Constructor Details
#initialize(size) ⇒ WorkerPool
Builds a pool.
21 22 23 |
# File 'lib/mutineer/worker_pool.rb', line 21 def initialize(size) @size = [size.to_i, 1].max end |
Instance Method Details
#run(items, stop_when: nil) {|item| ... } ⇒ Array<Mutineer::Result>
Runs the work items through the pool.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/mutineer/worker_pool.rb', line 34 def run(items, stop_when: nil) results = Array.new(items.size) queue = (0...items.size).to_a running = {} # pid => [index, read_io, buffer] stopping = false until queue.empty? && running.empty? fill(items, queue, running) { |*args| yield(*args) } unless stopping result = reap(results, running) if !stopping && stop_when && result && stop_when.call(result) stopping = true queue.clear # schedule no more; let in-flight workers drain end end results end |