async 2.28.1 → 2.32.0

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.
data/lib/async/queue.rb CHANGED
@@ -10,10 +10,14 @@
10
10
  require_relative "notification"
11
11
 
12
12
  module Async
13
- # A queue which allows items to be processed in order.
13
+ # A thread-safe queue which allows items to be processed in order.
14
+ #
15
+ # This implementation uses Thread::Queue internally for thread safety while
16
+ # maintaining compatibility with the fiber scheduler.
14
17
  #
15
18
  # It has a compatible interface with {Notification} and {Condition}, except that it's multi-value.
16
19
  #
20
+ # @asynchronous This class is thread-safe.
17
21
  # @public Since *Async v1*.
18
22
  class Queue
19
23
  # An error raised when trying to enqueue items to a closed queue.
@@ -21,53 +25,44 @@ module Async
21
25
  class ClosedError < RuntimeError
22
26
  end
23
27
 
24
- # Create a new queue.
28
+ # Create a new thread-safe queue.
25
29
  #
26
30
  # @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
27
- # @parameter available [Notification] The notification to use for signaling when items are available.
28
- def initialize(parent: nil, available: Notification.new)
29
- @items = []
30
- @closed = false
31
+ def initialize(parent: nil, delegate: Thread::Queue.new)
32
+ @delegate = delegate
31
33
  @parent = parent
32
- @available = available
33
34
  end
34
35
 
35
36
  # @returns [Boolean] Whether the queue is closed.
36
37
  def closed?
37
- @closed
38
+ @delegate.closed?
38
39
  end
39
40
 
40
41
  # Close the queue, causing all waiting tasks to return `nil`. Any subsequent calls to {enqueue} will raise an exception.
41
42
  def close
42
- @closed = true
43
-
44
- while @available.waiting?
45
- @available.signal(nil)
46
- end
43
+ @delegate.close
47
44
  end
48
45
 
49
- # @attribute [Array] The items in the queue.
50
- attr :items
51
-
52
46
  # @returns [Integer] The number of items in the queue.
53
47
  def size
54
- @items.size
48
+ @delegate.size
55
49
  end
56
50
 
57
51
  # @returns [Boolean] Whether the queue is empty.
58
52
  def empty?
59
- @items.empty?
53
+ @delegate.empty?
54
+ end
55
+
56
+ # @returns [Integer] The number of tasks waiting for an item.
57
+ def waiting_count
58
+ @delegate.num_waiting
60
59
  end
61
60
 
62
61
  # Add an item to the queue.
63
62
  def push(item)
64
- if @closed
65
- raise ClosedError, "Cannot push items to a closed queue."
66
- end
67
-
68
- @items << item
69
-
70
- @available.signal unless self.empty?
63
+ @delegate.push(item)
64
+ rescue ClosedQueueError
65
+ raise ClosedError, "Cannot enqueue items to a closed queue!"
71
66
  end
72
67
 
73
68
  # Compatibility with {::Queue#push}.
@@ -77,31 +72,23 @@ module Async
77
72
 
78
73
  # Add multiple items to the queue.
79
74
  def enqueue(*items)
80
- if @closed
81
- raise ClosedError, "Cannot enqueue items to a closed queue."
82
- end
83
-
84
- @items.concat(items)
85
-
86
- @available.signal unless self.empty?
75
+ items.each {|item| @delegate.push(item)}
76
+ rescue ClosedQueueError
77
+ raise ClosedError, "Cannot enqueue items to a closed queue!"
87
78
  end
88
79
 
89
80
  # Remove and return the next item from the queue.
90
- def dequeue
91
- while @items.empty?
92
- if @closed
93
- return nil
94
- end
95
-
96
- @available.wait
97
- end
98
-
99
- @items.shift
81
+ # @parameter timeout [Numeric, nil] Maximum time to wait for an item. If nil, waits indefinitely. If 0, returns immediately.
82
+ # @returns [Object, nil] The dequeued item, or nil if timeout expires.
83
+ def dequeue(timeout: nil)
84
+ @delegate.pop(timeout: timeout)
100
85
  end
101
86
 
102
87
  # Compatibility with {::Queue#pop}.
103
- def pop
104
- self.dequeue
88
+ # @parameter timeout [Numeric, nil] Maximum time to wait for an item. If nil, waits indefinitely. If 0, returns immediately.
89
+ # @returns [Object, nil] The dequeued item, or nil if timeout expires.
90
+ def pop(timeout: nil)
91
+ @delegate.pop(timeout: timeout)
105
92
  end
106
93
 
107
94
  # Process each item in the queue.
@@ -136,7 +123,8 @@ module Async
136
123
  end
137
124
  end
138
125
 
139
- # A queue which limits the number of items that can be enqueued.
126
+ # A thread-safe queue which limits the number of items that can be enqueued.
127
+ #
140
128
  # @public Since *Async v1*.
141
129
  class LimitedQueue < Queue
142
130
  # @private This exists purely for emitting a warning.
@@ -149,78 +137,19 @@ module Async
149
137
  # Create a new limited queue.
150
138
  #
151
139
  # @parameter limit [Integer] The maximum number of items that can be enqueued.
152
- # @parameter full [Notification] The notification to use for signaling when the queue is full.
153
- def initialize(limit = 1, full: Notification.new, **options)
154
- super(**options)
155
-
156
- @limit = limit
157
- @full = full
140
+ # @parameter full [Notification] The notification to use for signaling when the queue is full. (ignored, for compatibility)
141
+ def initialize(limit = 1, **options)
142
+ super(**options, delegate: Thread::SizedQueue.new(limit))
158
143
  end
159
144
 
160
145
  # @attribute [Integer] The maximum number of items that can be enqueued.
161
- attr :limit
162
-
163
- # Close the queue, causing all waiting tasks to return `nil`. Any subsequent calls to {enqueue} will raise an exception.
164
- # Also signals all tasks waiting for the queue to be full.
165
- def close
166
- super
167
-
168
- while @full.waiting?
169
- @full.signal(nil)
170
- end
146
+ def limit
147
+ @delegate.max
171
148
  end
172
149
 
173
150
  # @returns [Boolean] Whether trying to enqueue an item would block.
174
151
  def limited?
175
- !@closed && @items.size >= @limit
176
- end
177
-
178
- # Add an item to the queue.
179
- #
180
- # If the queue is full, this method will block until there is space available.
181
- #
182
- # @parameter item [Object] The item to add to the queue.
183
- def push(item)
184
- while limited?
185
- @full.wait
186
- end
187
-
188
- super
189
- end
190
-
191
- # Add multiple items to the queue.
192
- #
193
- # If the queue is full, this method will block until there is space available.
194
- #
195
- # @parameter items [Array] The items to add to the queue.
196
- def enqueue(*items)
197
- while !items.empty?
198
- while limited?
199
- @full.wait
200
- end
201
-
202
- if @closed
203
- raise ClosedError, "Cannot enqueue items to a closed queue."
204
- end
205
-
206
- available = @limit - @items.size
207
- @items.concat(items.shift(available))
208
-
209
- @available.signal unless self.empty?
210
- end
211
- end
212
-
213
- # Remove and return the next item from the queue.
214
- #
215
- # If the queue is empty, this method will block until an item is available.
216
- #
217
- # @returns [Object] The next item in the queue.
218
- def dequeue
219
- item = super
220
-
221
- @full.signal
222
-
223
- return item
152
+ !@delegate.closed? && @delegate.size >= @delegate.max
224
153
  end
225
154
  end
226
155
  end
data/lib/async/task.rb CHANGED
@@ -7,12 +7,14 @@
7
7
  # Copyright, 2020, by Patrik Wenger.
8
8
  # Copyright, 2023, by Math Ieu.
9
9
  # Copyright, 2025, by Shigeru Nakajima.
10
+ # Copyright, 2025, by Shopify Inc.
10
11
 
11
12
  require "fiber"
12
13
  require "console"
13
14
 
14
15
  require_relative "node"
15
16
  require_relative "condition"
17
+ require_relative "promise"
16
18
  require_relative "stop"
17
19
 
18
20
  Fiber.attr_accessor :async_task
@@ -63,14 +65,24 @@ module Async
63
65
 
64
66
  # These instance variables are critical to the state of the task.
65
67
  # In the initialized state, the @block should be set, but the @fiber should be nil.
66
- # In the running state, the @fiber should be set.
68
+ # In the running state, the @fiber should be set, and @block should be nil.
67
69
  # In a finished state, the @block should be nil, and the @fiber should be nil.
68
70
  @block = block
69
71
  @fiber = nil
70
72
 
71
- @status = :initialized
72
- @result = nil
73
- @finished = finished
73
+ @promise = Promise.new
74
+
75
+ # Handle finished: parameter for backward compatibility:
76
+ case finished
77
+ when false
78
+ # `finished: false` suppresses warnings for expected task failures:
79
+ @promise.suppress_warnings!
80
+ when nil
81
+ # `finished: nil` is the default, no special handling:
82
+ else
83
+ # All other `finished:` values are deprecated:
84
+ warn("finished: argument with non-false value is deprecated and will be removed.", uplevel: 1, category: :deprecated) if $VERBOSE
85
+ end
74
86
 
75
87
  @defer_stop = nil
76
88
  end
@@ -109,7 +121,7 @@ module Async
109
121
 
110
122
  # @returns [String] A description of the task and it's current status.
111
123
  def to_s
112
- "\#<#{self.description} (#{@status})>"
124
+ "\#<#{self.description} (#{self.status})>"
113
125
  end
114
126
 
115
127
  # @deprecated Prefer {Kernel#sleep} except when compatibility with `stable-v1` is required.
@@ -146,22 +158,22 @@ module Async
146
158
 
147
159
  # @returns [Boolean] Whether the task is running.
148
160
  def running?
149
- @status == :running
161
+ self.alive?
150
162
  end
151
163
 
152
164
  # @returns [Boolean] Whether the task failed with an exception.
153
165
  def failed?
154
- @status == :failed
166
+ @promise.failed?
155
167
  end
156
168
 
157
169
  # @returns [Boolean] Whether the task has been stopped.
158
170
  def stopped?
159
- @status == :stopped
171
+ @promise.cancelled?
160
172
  end
161
173
 
162
174
  # @returns [Boolean] Whether the task has completed execution and generated a result.
163
175
  def completed?
164
- @status == :completed
176
+ @promise.completed?
165
177
  end
166
178
 
167
179
  # Alias for {#completed?}.
@@ -170,20 +182,32 @@ module Async
170
182
  end
171
183
 
172
184
  # @attribute [Symbol] The status of the execution of the task, one of `:initialized`, `:running`, `:complete`, `:stopped` or `:failed`.
173
- attr :status
185
+ def status
186
+ case @promise.resolved
187
+ when :cancelled
188
+ :stopped
189
+ when :failed
190
+ :failed
191
+ when :completed
192
+ :completed
193
+ when nil
194
+ self.running? ? :running : :initialized
195
+ end
196
+ end
174
197
 
175
198
  # Begin the execution of the task.
176
199
  #
177
200
  # @raises [RuntimeError] If the task is already running.
178
201
  def run(*arguments)
179
- if @status == :initialized
180
- @status = :running
202
+ # Move from initialized to running by clearing @block
203
+ if block = @block
204
+ @block = nil
181
205
 
182
206
  schedule do
183
- @block.call(self, *arguments)
207
+ block.call(self, *arguments)
184
208
  rescue => error
185
209
  # I'm not completely happy with this overhead, but the alternative is to not log anything which makes debugging extremely difficult. Maybe we can introduce a debug wrapper which adds extra logging.
186
- if @finished.nil?
210
+ unless @promise.waiting?
187
211
  warn(self, "Task may have ended with unhandled exception.", exception: error)
188
212
  end
189
213
 
@@ -225,24 +249,29 @@ module Async
225
249
  #
226
250
  # @raises [RuntimeError] If the task's fiber is the current fiber.
227
251
  # @returns [Object] The final expression/result of the task's block.
252
+ # @asynchronous This method is thread-safe.
228
253
  def wait
229
254
  raise "Cannot wait on own fiber!" if Fiber.current.equal?(@fiber)
230
255
 
231
- # `finish!` will set both of these to nil before signaling the condition:
232
- if @block || @fiber
233
- @finished ||= Condition.new
234
- @finished.wait
235
- end
236
-
237
- if @status == :failed
238
- raise @result
239
- else
240
- return @result
256
+ # Wait for the task to complete - Promise handles all the complexity:
257
+ begin
258
+ @promise.wait
259
+ rescue Promise::Cancel
260
+ # For backward compatibility, stopped tasks return nil
261
+ return nil
241
262
  end
242
263
  end
243
264
 
244
265
  # Access the result of the task without waiting. May be nil if the task is not completed. Does not raise exceptions.
245
- attr :result
266
+ def result
267
+ value = @promise.value
268
+ # For backward compatibility, return nil for stopped tasks
269
+ if @promise.cancelled?
270
+ nil
271
+ else
272
+ value
273
+ end
274
+ end
246
275
 
247
276
  # Stop the task and all of its children.
248
277
  #
@@ -375,29 +404,25 @@ module Async
375
404
 
376
405
  # Attempt to remove this node from the task tree.
377
406
  consume
378
-
379
- # If this task was being used as a future, signal completion here:
380
- if @finished
381
- @finished.signal(self)
382
- @finished = nil
383
- end
384
407
  end
385
408
 
386
409
  # State transition into the completed state.
387
410
  def completed!(result)
388
- @result = result
389
- @status = :completed
411
+ # Resolve the promise with the result:
412
+ @promise&.resolve(result)
390
413
  end
391
414
 
392
415
  # State transition into the failed state.
393
416
  def failed!(exception = false)
394
- @result = exception
395
- @status = :failed
417
+ # Reject the promise with the exception:
418
+ @promise&.reject(exception)
396
419
  end
397
420
 
398
421
  def stopped!
399
422
  # Console.info(self, status:) {"Task #{self} was stopped with #{@children&.size.inspect} children!"}
400
- @status = :stopped
423
+
424
+ # Cancel the promise:
425
+ @promise&.cancel
401
426
 
402
427
  stopped = false
403
428
 
@@ -442,7 +467,7 @@ module Async
442
467
 
443
468
  @fiber.async_task = self
444
469
 
445
- self.root.resume(@fiber)
470
+ (Fiber.scheduler || self.reactor).resume(@fiber)
446
471
  end
447
472
  end
448
473
  end
@@ -2,16 +2,21 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2021-2025, by Samuel Williams.
5
+ # Copyright, 2025, by Shopify Inc.
5
6
 
6
7
  require_relative "condition"
7
8
 
8
9
  module Async
9
10
  # A synchronization primitive that allows one task to wait for another task to resolve a value.
11
+ #
12
+ # @deprecated Use {Async::Promise} instead.
10
13
  class Variable
11
14
  # Create a new variable.
12
15
  #
13
16
  # @parameter condition [Condition] The condition to use for synchronization.
14
17
  def initialize(condition = Condition.new)
18
+ warn("`Async::Variable` is deprecated, use `Async::Promise` instead.", category: :deprecated, uplevel: 1) if $VERBOSE
19
+
15
20
  @condition = condition
16
21
  @value = nil
17
22
  end
data/lib/async/version.rb CHANGED
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2017-2025, by Samuel Williams.
5
5
 
6
6
  module Async
7
- VERSION = "2.28.1"
7
+ VERSION = "2.32.0"
8
8
  end
data/lib/async/waiter.rb CHANGED
@@ -3,9 +3,11 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2022-2025, by Samuel Williams.
5
5
  # Copyright, 2024, by Patrik Wenger.
6
+ # Copyright, 2025, by Shopify Inc.
6
7
 
7
8
  module Async
8
9
  # A composable synchronization primitive, which allows one task to wait for a number of other tasks to complete. It can be used in conjunction with {Semaphore} and/or {Barrier}.
10
+ #
9
11
  # @deprecated `Async::Waiter` is deprecated, use `Async::Barrier` instead.
10
12
  class Waiter
11
13
  # Create a waiter instance.
data/lib/kernel/sync.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
  # Copyright, 2020, by Brian Morearty.
6
6
  # Copyright, 2024, by Patrik Wenger.
7
+ # Copyright, 2025, by Shopify Inc.
7
8
 
8
9
  require_relative "../async/reactor"
9
10
 
@@ -30,7 +31,10 @@ module Kernel
30
31
  reactor = Async::Reactor.new
31
32
 
32
33
  begin
33
- return reactor.run(annotation: annotation, finished: ::Async::Condition.new, &block).wait
34
+ # Use finished: false to suppress warnings since we're handling exceptions explicitly
35
+ task = reactor.async(annotation: annotation, finished: false, &block)
36
+ reactor.run
37
+ return task.wait
34
38
  ensure
35
39
  Fiber.set_scheduler(nil)
36
40
  end
data/readme.md CHANGED
@@ -35,6 +35,31 @@ Please see the [project documentation](https://socketry.github.io/async/) for mo
35
35
 
36
36
  Please see the [project releases](https://socketry.github.io/async/releases/index) for all releases.
37
37
 
38
+ ### v2.32.0
39
+
40
+ - Introduce `Queue#waiting_count` and `PriorityQueue#waiting_count`. Generally for statistics/testing purposes only.
41
+
42
+ ### v2.31.0
43
+
44
+ - Introduce `Async::Deadline` for precise timeout management in compound operations.
45
+
46
+ ### v2.30.0
47
+
48
+ - Add timeout support to `Async::Queue#dequeue` and `Async::Queue#pop` methods.
49
+ - Add timeout support to `Async::PriorityQueue#dequeue` and `Async::PriorityQueue#pop` methods.
50
+ - Add `closed?` method to `Async::PriorityQueue` for full queue interface compatibility.
51
+ - Support non-blocking operations using `timeout: 0` parameter.
52
+
53
+ ### v2.29.0
54
+
55
+ This release introduces thread-safety as a core concept of Async. Many core classes now have thread-safe guarantees, allowing them to be used safely across multiple threads.
56
+
57
+ - Thread-safe `Async::Condition` and `Async::Notification`, implemented using `Thread::Queue`.
58
+ - Thread-safe `Async::Queue` and `Async::LimitedQueue`, implemented using `Thread::Queue` and `Thread::LimitedQueue` respectively.
59
+ - `Async::Variable` is deprecated in favor of `Async::Promise`.
60
+ - [Introduce `Async::Promise`](https://socketry.github.io/async/releases/index#introduce-async::promise)
61
+ - [Introduce `Async::PriorityQueue`](https://socketry.github.io/async/releases/index#introduce-async::priorityqueue)
62
+
38
63
  ### v2.28.1
39
64
 
40
65
  - Fix race condition between `Async::Barrier#stop` and finish signalling.
@@ -59,34 +84,6 @@ Please see the [project releases](https://socketry.github.io/async/releases/inde
59
84
 
60
85
  - Updated documentation and agent context.
61
86
 
62
- ### v2.27.0
63
-
64
- - `Async::Task#stop` supports an optional `cause:` argument (that defaults to `$!`), which allows you to specify the cause (exception) for stopping the task.
65
- - Add thread-safety agent context.
66
-
67
- ### v2.26.0
68
-
69
- - `Async::Notification#signal` now returns `true` if a task was signaled, `false` otherwise, providing better feedback for notification operations.
70
- - `require "async/limited_queue"` is required to use `Async::LimitedQueue` without a deprecation warning. `Async::LimitedQueue` is not deprecated, but it's usage via `async/queue` is deprecated.
71
- - `Async::Task#sleep` is deprecated with no replacement.
72
- - `Async::Task.yield` is deprecated with no replacement.
73
- - `Async::Scheduler#async` is deprecated, use `Async{}`, `Sync{}` or `Async::Task#async` instead.
74
- - Agent context is now available, via the [`agent-context` gem](https://github.com/ioquatix/agent-context).
75
- - [`Async::Barrier` Improvements](https://socketry.github.io/async/releases/index#async::barrier-improvements)
76
- - [Introduce `Async::Queue#close`](https://socketry.github.io/async/releases/index#introduce-async::queue#close)
77
-
78
- ### v2.25.0
79
-
80
- - Added support for `io_select` hook in the fiber scheduler, allowing non-blocking `IO.select` operations. This enables better integration with code that uses `IO.select` for multiplexing IO operations.
81
- - [Use `IO::Event::WorkerPool` for Blocking Operations](https://socketry.github.io/async/releases/index#use-io::event::workerpool-for-blocking-operations)
82
- - [Better handling of `IO#close` using `fiber_interrupt`](https://socketry.github.io/async/releases/index#better-handling-of-io#close-using-fiber_interrupt)
83
-
84
- ### v2.24.0
85
-
86
- - Ruby v3.1 support is dropped.
87
- - `Async::Wrapper` which was previously deprecated, is now removed.
88
- - [Flexible Timeouts](https://socketry.github.io/async/releases/index#flexible-timeouts)
89
-
90
87
  ## See Also
91
88
 
92
89
  - [async-http](https://github.com/socketry/async-http) — Asynchronous HTTP client/server.
data/releases.md CHANGED
@@ -1,5 +1,98 @@
1
1
  # Releases
2
2
 
3
+ ## v2.32.0
4
+
5
+ - Introduce `Queue#waiting_count` and `PriorityQueue#waiting_count`. Generally for statistics/testing purposes only.
6
+
7
+ ## v2.31.0
8
+
9
+ - Introduce `Async::Deadline` for precise timeout management in compound operations.
10
+
11
+ ## v2.30.0
12
+
13
+ - Add timeout support to `Async::Queue#dequeue` and `Async::Queue#pop` methods.
14
+ - Add timeout support to `Async::PriorityQueue#dequeue` and `Async::PriorityQueue#pop` methods.
15
+ - Add `closed?` method to `Async::PriorityQueue` for full queue interface compatibility.
16
+ - Support non-blocking operations using `timeout: 0` parameter.
17
+
18
+ ## v2.29.0
19
+
20
+ This release introduces thread-safety as a core concept of Async. Many core classes now have thread-safe guarantees, allowing them to be used safely across multiple threads.
21
+
22
+ - Thread-safe `Async::Condition` and `Async::Notification`, implemented using `Thread::Queue`.
23
+ - Thread-safe `Async::Queue` and `Async::LimitedQueue`, implemented using `Thread::Queue` and `Thread::LimitedQueue` respectively.
24
+ - `Async::Variable` is deprecated in favor of `Async::Promise`.
25
+
26
+ ### Introduce `Async::Promise`
27
+
28
+ This release introduces the new `Async::Promise` class and refactors `Async::Task` to use promises for state management internally. This architectural improvement achieves the design goal that "a task should be a promise with attached computation and cancellation handling."
29
+
30
+ - **Thread-safe promise implementation** with immutable state transitions.
31
+ - **Consistent state management** using symbols: `:completed`, `:failed`, `:cancelled`.
32
+ - **Promise cancellation** with `cancel()` method and `Cancel` exception class.
33
+ - **Comprehensive test coverage** with 47 new test cases covering all edge cases.
34
+
35
+ <!-- end list -->
36
+
37
+ ``` ruby
38
+ require 'async/promise'
39
+
40
+ # Basic promise usage - works independently of Async framework
41
+ promise = Async::Promise.new
42
+
43
+ # In another thread or fiber, resolve the promise
44
+ Thread.new do
45
+ sleep(1) # Simulate some work
46
+ promise.resolve("Hello, World!")
47
+ end
48
+
49
+ # Wait for the result
50
+ result = promise.wait
51
+ puts result # => "Hello, World!"
52
+
53
+ # Check promise state
54
+ puts promise.resolved? # => true
55
+ puts promise.completed? # => true
56
+ ```
57
+
58
+ Promises bridge Thread and Fiber concurrency models - a promise resolved in one thread can be awaited in a fiber, and vice versa.
59
+
60
+ ### Introduce `Async::PriorityQueue`
61
+
62
+ The new `Async::PriorityQueue` provides a thread-safe, fiber-aware queue where consumers can specify priority levels. Higher priority consumers are served first when items become available, with FIFO ordering maintained for equal priorities. This is useful for implementing priority-based task processing systems where critical operations need to be handled before lower priority work.
63
+
64
+ ``` ruby
65
+ require 'async'
66
+ require 'async/priority_queue'
67
+
68
+ Async do
69
+ queue = Async::PriorityQueue.new
70
+
71
+ # Start consumers with different priorities
72
+ low_priority = async do
73
+ puts "Low priority consumer got: #{queue.dequeue(priority: 1)}"
74
+ end
75
+
76
+ medium_priority = async do
77
+ puts "Medium priority consumer got: #{queue.dequeue(priority: 5)}"
78
+ end
79
+
80
+ high_priority = async do
81
+ puts "High priority consumer got: #{queue.dequeue(priority: 10)}"
82
+ end
83
+
84
+ # Add items to the queue
85
+ queue.push("first item")
86
+ queue.push("second item")
87
+ queue.push("third item")
88
+
89
+ # Output:
90
+ # High priority consumer got: first item
91
+ # Medium priority consumer got: second item
92
+ # Low priority consumer got: third item
93
+ end
94
+ ```
95
+
3
96
  ## v2.28.1
4
97
 
5
98
  - Fix race condition between `Async::Barrier#stop` and finish signalling.
data.tar.gz.sig CHANGED
@@ -1,2 +1,2 @@
1
- =��؃��6���{ �/�hܯ+�t��������y���� %��h�AY�|�uc{��Y'����Z�<;0����E�#d&�xw�f���� �J?���5r ��S��o���R0��4��3H����yD��Ɨ<���d��h�7�~"Ê�~�?[�#�XU�+l{�
2
- ��Pz; ��
1
+ ���\��v�]3^į38��h�V��&,���a�j�5P��th���)'��C��,� AGp���G#�zi )c��d���n��.:���檾A�|F~O^�D�Ж���,���Z46J!{���m���6���pk~S
2
+ {z+�s������_ԗ�����i�B��lv�w��ӛQ~9p��_�m������2���)r�e}M�u��Y��IL;�����ҳ��C_zɀt�����ͦ/�����+��� �}�ve7��F�94�0� 6"�� eڜ���+s�Oz�RL���;hGS��#Q{���=~2=n��?P�;��Xy��N(6�%��~��^��\�M\��N��񮡼�����>I/6D��ƍ��