ractor-pool 0.4.0 → 0.4.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d8741738f0de76db49cbbbaccc701b687af3df13ce9802205c7661a10519126
4
- data.tar.gz: 337ce4d26b7735ec2517c2b88e76f2b11bef87124e3581a74772e68fbd3b6e57
3
+ metadata.gz: 2c1dea8867f0e74c842abc4eb14e058be7361695a0e280ac02e57663a6bc461d
4
+ data.tar.gz: f1b7d5d10dbc898a84990907625aeace403cb2d053fcce42947856aba64631e6
5
5
  SHA512:
6
- metadata.gz: 663d3b28aeab7e0341bbfd5d78540c670fbb74e3cfc89679572093067fc72396028d3b1637c224676d4c52d86aaafd688143e28499217f0b513c7d5035ba42c4
7
- data.tar.gz: 6a9fc3ec933ece355f9bba48ac1de2980a3c105f0baaf2a13684ab74a54028daec5f2695dee25c4d970d3dc71f7bd066d207977424f8f199c44f8f61e9e6ae85
6
+ metadata.gz: 3c07ae252a879363467f3d085bfbe573941bc2d733d6ab67a20a18b903f3acdc700404e7abdbacb8bb88b24246b3254898b207fde24605e25049dd1e72dd03e8
7
+ data.tar.gz: 1b4186600d78d0a4df2e84f4cb895de318c9562e5eed118b297e28109c8db3da0f1450230c76c5e1fbf8673e5ed670f74302044d695a8e339b0198c433c55354
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.2] - 2026-10-18
4
+
5
+ - Collect worker results and errors on one thread
6
+
7
+ ## [0.4.1] - 2026-07-20
8
+
9
+ - Name the underlying thread of each worker and coordinator `Ractor`
10
+
3
11
  ## [0.4.0] - 2026-05-20
4
12
 
5
13
  - Add `:round_robin` dispatch strategy
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class RactorPool
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.2"
5
5
  end
data/lib/ractor-pool.rb CHANGED
@@ -59,6 +59,9 @@ class RactorPool
59
59
  SHUTDOWN = :shutdown
60
60
  private_constant :SHUTDOWN
61
61
 
62
+ WorkerError = Data.define(:full_message)
63
+ private_constant :WorkerError
64
+
62
65
  # @rbs @size: Integer
63
66
  # @rbs @worker: ^(untyped) -> untyped
64
67
  # @rbs @strategy: Symbol
@@ -68,12 +71,10 @@ class RactorPool
68
71
  # @rbs @in_flight: Atom[Integer]
69
72
  # @rbs @shutdown: Atom[bool]
70
73
  # @rbs @next_worker_index: Atom[Integer]?
71
- # @rbs @result_port: Ractor::Port?
72
- # @rbs @error_port: Ractor::Port?
74
+ # @rbs @collector_port: Ractor::Port?
73
75
  # @rbs @coordinator: Ractor?
74
76
  # @rbs @workers: Array[Ractor]
75
77
  # @rbs @collector: Thread?
76
- # @rbs @error_collector: Thread?
77
78
 
78
79
  # Creates a new RactorPool with the specified number of workers.
79
80
  #
@@ -121,12 +122,10 @@ class RactorPool
121
122
  @shutdown = Atom.new(false)
122
123
  @next_worker_index = Atom.new(-1) if size > 1 && strategy == :round_robin
123
124
 
124
- @result_port = Ractor::Port.new if result_handler
125
- @error_port = Ractor::Port.new unless on_error
125
+ @collector_port = Ractor::Port.new if result_handler || !on_error
126
126
  @coordinator = start_coordinator if size > 1 && strategy == :coordinator
127
127
  @workers = start_workers
128
128
  @collector = start_collector
129
- @error_collector = start_error_collector
130
129
  end
131
130
 
132
131
  # Queues a work item to be processed by an available worker.
@@ -203,10 +202,8 @@ class RactorPool
203
202
  else
204
203
  @workers.each { |worker| worker.send(SHUTDOWN, move: true) }
205
204
  @workers.each(&:join)
206
- @result_port&.send(SHUTDOWN, move: true)
205
+ @collector_port&.send(SHUTDOWN, move: true)
207
206
  end
208
- @error_port&.send(SHUTDOWN, move: true)
209
- @error_collector&.join
210
207
  @collector&.join
211
208
  end
212
209
 
@@ -217,7 +214,12 @@ class RactorPool
217
214
  ractor_name = String.new("#{self.class.name} coordinator ractor")
218
215
  ractor_name << " for #{@name}" if @name
219
216
 
220
- Ractor.new(@size, @result_port, name: ractor_name) do |worker_count, result_port|
217
+ thread_name = String.new("#{self.class.name} coordinator thread")
218
+ thread_name << " for #{@name}" if @name
219
+
220
+ Ractor.new(@size, @collector_port, thread_name, name: ractor_name) do |worker_count, collector_port, thread_name|
221
+ Thread.current.name = thread_name
222
+
221
223
  work_queue = []
222
224
  waiting_workers = []
223
225
  shutdown_received = false
@@ -232,7 +234,7 @@ class RactorPool
232
234
  waiting_workers.each { |worker| worker.send(SHUTDOWN, move: true) }
233
235
  waiting_workers.clear
234
236
  if workers_finished == worker_count
235
- result_port&.send(SHUTDOWN, move: true)
237
+ collector_port&.send(SHUTDOWN, move: true)
236
238
  break
237
239
  end
238
240
 
@@ -246,7 +248,7 @@ class RactorPool
246
248
 
247
249
  workers_finished += 1
248
250
  if workers_finished == worker_count
249
- result_port&.send(SHUTDOWN, move: true)
251
+ collector_port&.send(SHUTDOWN, move: true)
250
252
  break
251
253
  end
252
254
  else
@@ -268,11 +270,19 @@ class RactorPool
268
270
 
269
271
  # @rbs () -> Array[Ractor]
270
272
  def start_workers
273
+ result_port = @collector_port if @result_handler
274
+ error_port = @collector_port unless @on_error
275
+
271
276
  @size.times.map do |index|
272
277
  ractor_name = String.new("#{self.class.name} ractor #{index}")
273
278
  ractor_name << " for #{@name}" if @name
274
279
 
275
- Ractor.new(@worker, @on_error, @error_port, @coordinator, @result_port, name: ractor_name) do |worker, on_error, error_port, coordinator, result_port|
280
+ thread_name = String.new("#{self.class.name} worker thread #{index}")
281
+ thread_name << " for #{@name}" if @name
282
+
283
+ Ractor.new(@worker, @on_error, error_port, @coordinator, result_port, thread_name, name: ractor_name) do |worker, on_error, error_port, coordinator, result_port, thread_name|
284
+ Thread.current.name = thread_name
285
+
276
286
  loop do
277
287
  coordinator&.send(Ractor.current, move: true)
278
288
 
@@ -284,7 +294,7 @@ class RactorPool
284
294
 
285
295
  result_port&.send(result, move: true)
286
296
  rescue => error
287
- on_error ? on_error.call(error) : error_port.send(error.full_message, move: true)
297
+ on_error ? on_error.call(error) : error_port.send(WorkerError.new(full_message: error.full_message), move: true)
288
298
  end
289
299
  end
290
300
  end
@@ -293,38 +303,23 @@ class RactorPool
293
303
 
294
304
  # @rbs () -> Thread?
295
305
  def start_collector
296
- return unless @result_handler
306
+ return unless @collector_port
297
307
 
298
308
  thread_name = String.new("#{self.class.name} collector thread")
299
309
  thread_name << " for #{@name}" if @name
300
310
 
301
- Thread.new(@result_port, @result_handler, thread_name) do |result_port, result_handler, name|
311
+ Thread.new(@collector_port, @result_handler, thread_name) do |collector_port, result_handler, name|
302
312
  Thread.current.name = name
303
313
 
304
314
  loop do
305
- result = result_port.receive
306
- break if result == SHUTDOWN
307
-
308
- result_handler.call(result)
309
- end
310
- end
311
- end
312
-
313
- # @rbs () -> Thread?
314
- def start_error_collector
315
- return if @on_error
316
-
317
- thread_name = String.new("#{self.class.name} error collector thread")
318
- thread_name << " for #{@name}" if @name
319
-
320
- Thread.new(@error_port, thread_name) do |error_port, name|
321
- Thread.current.name = name
322
-
323
- loop do
324
- message = error_port.receive
325
- break if message == SHUTDOWN
326
-
327
- warn message
315
+ case message = collector_port.receive
316
+ when SHUTDOWN
317
+ break
318
+ when WorkerError
319
+ warn message.full_message
320
+ else
321
+ result_handler.call(message)
322
+ end
328
323
  end
329
324
  end
330
325
  end
@@ -51,7 +51,16 @@ class RactorPool
51
51
 
52
52
  SHUTDOWN: ::Symbol
53
53
 
54
- @error_collector: Thread?
54
+ class WorkerError < Data
55
+ attr_reader full_message(): untyped
56
+
57
+ def self.new: (untyped full_message) -> instance
58
+ | (full_message: untyped) -> instance
59
+
60
+ def self.members: () -> [ :full_message ]
61
+
62
+ def members: () -> [ :full_message ]
63
+ end
55
64
 
56
65
  @collector: Thread?
57
66
 
@@ -59,9 +68,7 @@ class RactorPool
59
68
 
60
69
  @coordinator: Ractor?
61
70
 
62
- @error_port: Ractor::Port?
63
-
64
- @result_port: Ractor::Port?
71
+ @collector_port: Ractor::Port?
65
72
 
66
73
  @next_worker_index: Atom[Integer]?
67
74
 
@@ -154,7 +161,4 @@ class RactorPool
154
161
 
155
162
  # @rbs () -> Thread?
156
163
  def start_collector: () -> Thread?
157
-
158
- # @rbs () -> Thread?
159
- def start_error_collector: () -> Thread?
160
164
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ractor-pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Young
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  requirements: []
76
- rubygems_version: 4.0.10
76
+ rubygems_version: 4.0.20
77
77
  specification_version: 4
78
78
  summary: A thread-safe, lock-free pool of Ractor workers with coordinator or round-robin
79
79
  dispatch for distributing work