async 2.25.0 → 2.26.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/agent.md +47 -0
- data/lib/async/barrier.md +0 -1
- data/lib/async/barrier.rb +30 -9
- data/lib/async/condition.rb +2 -0
- data/lib/async/limited_queue.rb +6 -0
- data/lib/async/list.rb +9 -2
- data/lib/async/node.rb +1 -0
- data/lib/async/notification.rb +5 -3
- data/lib/async/queue.rb +49 -1
- data/lib/async/reactor.rb +2 -0
- data/lib/async/scheduler.rb +6 -1
- data/lib/async/task.rb +4 -0
- data/lib/async/version.rb +1 -1
- data/lib/async/waiter.rb +3 -0
- data/lib/traces/provider/async/barrier.rb +1 -1
- data/readme.md +12 -1
- data/releases.md +84 -2
- data.tar.gz.sig +0 -0
- metadata +5 -5
- metadata.gz.sig +0 -0
- data/lib/async/waiter.md +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c593ddf06be9954e63b4f85eb8c0fe022be6cf1e241a37f86620a82fdf860b3
|
4
|
+
data.tar.gz: 023b1544a36d3bb8ff85f0b8cc3ccc0b4694ed3b0542ed7dafd02330f05ee663
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65c3fee1ef33362307c4c74dd2451384de1e1747041ffd68cec0049465a317dada93083198254b905e89758a112800894436fe4cc8a2c713b0c0f5de1a36402e
|
7
|
+
data.tar.gz: a90fa15643b4a491599e95429c0d79da4363d0778455a50893ee9d6f34217ebd442bf99085f981807e024dfec561f545ea86d74e06f2874b34c1bd191a1b79fa
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/agent.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Agent
|
2
|
+
|
3
|
+
## Context
|
4
|
+
|
5
|
+
This section provides links to documentation from installed packages. It is automatically generated and may be updated by running `bake agent:context:install`.
|
6
|
+
|
7
|
+
**Important:** Before performing any code, documentation, or analysis tasks, always read and apply the full content of any relevant documentation referenced in the following sections. These context files contain authoritative standards and best practices for documentation, code style, and project-specific workflows. **Do not proceed with any actions until you have read and incorporated the guidance from relevant context files.**
|
8
|
+
|
9
|
+
### agent-context
|
10
|
+
|
11
|
+
Install and manage context files from Ruby gems.
|
12
|
+
|
13
|
+
#### [Usage Guide](.context/agent-context/usage.md)
|
14
|
+
|
15
|
+
`agent-context` is a tool that helps you discover and install contextual information from Ruby gems for AI agents. Gems can provide additional documentation, examples, and guidance in a `context/` ...
|
16
|
+
|
17
|
+
### decode
|
18
|
+
|
19
|
+
Code analysis for documentation generation.
|
20
|
+
|
21
|
+
#### [Getting Started with Decode](.context/decode/getting-started.md)
|
22
|
+
|
23
|
+
The Decode gem provides programmatic access to Ruby code structure and metadata. It can parse Ruby files and extract definitions, comments, and documentation pragmas, enabling code analysis, docume...
|
24
|
+
|
25
|
+
#### [Documentation Coverage](.context/decode/coverage.md)
|
26
|
+
|
27
|
+
This guide explains how to test and monitor documentation coverage in your Ruby projects using the Decode gem's built-in bake tasks.
|
28
|
+
|
29
|
+
#### [Ruby Documentation](.context/decode/ruby-documentation.md)
|
30
|
+
|
31
|
+
This guide covers documentation practices and pragmas supported by the Decode gem for documenting Ruby code. These pragmas provide structured documentation that can be parsed and used to generate A...
|
32
|
+
|
33
|
+
### sus
|
34
|
+
|
35
|
+
A fast and scalable test runner.
|
36
|
+
|
37
|
+
#### [Using Sus Testing Framework](.context/sus/usage.md)
|
38
|
+
|
39
|
+
Sus is a modern Ruby testing framework that provides a clean, BDD-style syntax for writing tests. It's designed to be fast, simple, and expressive.
|
40
|
+
|
41
|
+
#### [Mocking](.context/sus/mocking.md)
|
42
|
+
|
43
|
+
There are two types of mocking in sus: `receive` and `mock`. The `receive` matcher is a subset of full mocking and is used to set expectations on method calls, while `mock` can be used to replace m...
|
44
|
+
|
45
|
+
#### [Shared Test Behaviors and Fixtures](.context/sus/shared.md)
|
46
|
+
|
47
|
+
Sus provides shared test contexts which can be used to define common behaviours or tests that can be reused across one or more test files.
|
data/lib/async/barrier.md
CHANGED
data/lib/async/barrier.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2019-
|
4
|
+
# Copyright, 2019-2025, by Samuel Williams.
|
5
5
|
|
6
6
|
require_relative "list"
|
7
7
|
require_relative "task"
|
8
|
+
require_relative "queue"
|
8
9
|
|
9
10
|
module Async
|
10
11
|
# A general purpose synchronisation primitive, which allows one task to wait for a number of other tasks to complete. It can be used in conjunction with {Semaphore}.
|
@@ -16,6 +17,7 @@ module Async
|
|
16
17
|
# @public Since *Async v1*.
|
17
18
|
def initialize(parent: nil)
|
18
19
|
@tasks = List.new
|
20
|
+
@finished = Queue.new
|
19
21
|
|
20
22
|
@parent = parent
|
21
23
|
end
|
@@ -41,11 +43,15 @@ module Async
|
|
41
43
|
# Execute a child task and add it to the barrier.
|
42
44
|
# @asynchronous Executes the given block concurrently.
|
43
45
|
def async(*arguments, parent: (@parent or Task.current), **options, &block)
|
44
|
-
|
46
|
+
waiting = nil
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
parent.async(*arguments, **options) do |task, *arguments|
|
49
|
+
waiting = TaskNode.new(task)
|
50
|
+
@tasks.append(waiting)
|
51
|
+
block.call(task, *arguments)
|
52
|
+
ensure
|
53
|
+
@finished.signal(waiting)
|
54
|
+
end
|
49
55
|
end
|
50
56
|
|
51
57
|
# Whether there are any tasks being held by the barrier.
|
@@ -55,14 +61,27 @@ module Async
|
|
55
61
|
end
|
56
62
|
|
57
63
|
# Wait for all tasks to complete by invoking {Task#wait} on each waiting task, which may raise an error. As long as the task has completed, it will be removed from the barrier.
|
64
|
+
#
|
65
|
+
# @yields {|task| ...} If a block is given, the unwaited task is yielded. You must invoke {Task#wait} yourself. In addition, you may `break` if you have captured enough results.
|
66
|
+
#
|
58
67
|
# @asynchronous Will wait for tasks to finish executing.
|
59
68
|
def wait
|
60
|
-
|
69
|
+
while !@tasks.empty?
|
70
|
+
# Wait for a task to finish (we get the task node):
|
71
|
+
return unless waiting = @finished.wait
|
72
|
+
|
73
|
+
# Remove the task as it is now finishing:
|
74
|
+
@tasks.remove?(waiting)
|
75
|
+
|
76
|
+
# Get the task:
|
61
77
|
task = waiting.task
|
62
|
-
|
78
|
+
|
79
|
+
# If a block is given, the user can implement their own behaviour:
|
80
|
+
if block_given?
|
81
|
+
yield task
|
82
|
+
else
|
83
|
+
# Wait for it to either complete or raise an error:
|
63
84
|
task.wait
|
64
|
-
ensure
|
65
|
-
@tasks.remove?(waiting) unless task.alive?
|
66
85
|
end
|
67
86
|
end
|
68
87
|
end
|
@@ -73,6 +92,8 @@ module Async
|
|
73
92
|
@tasks.each do |waiting|
|
74
93
|
waiting.task.stop
|
75
94
|
end
|
95
|
+
|
96
|
+
@finished.close
|
76
97
|
end
|
77
98
|
end
|
78
99
|
end
|
data/lib/async/condition.rb
CHANGED
data/lib/async/limited_queue.rb
CHANGED
data/lib/async/list.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2022-
|
4
|
+
# Copyright, 2022-2025, by Samuel Williams.
|
5
5
|
|
6
6
|
module Async
|
7
7
|
# A general doublely linked list. This is used internally by {Async::Barrier} and {Async::Condition} to manage child tasks.
|
@@ -18,6 +18,7 @@ module Async
|
|
18
18
|
sprintf("#<%s:0x%x size=%d>", self.class.name, object_id, @size)
|
19
19
|
end
|
20
20
|
|
21
|
+
# @returns [String] A short summary of the list.
|
21
22
|
alias inspect to_s
|
22
23
|
|
23
24
|
# Fast, safe, unbounded accumulation of children.
|
@@ -134,7 +135,7 @@ module Async
|
|
134
135
|
return removed(node)
|
135
136
|
end
|
136
137
|
|
137
|
-
# @returns [Boolean]
|
138
|
+
# @returns [Boolean] True if the list is empty.
|
138
139
|
def empty?
|
139
140
|
@size == 0
|
140
141
|
end
|
@@ -238,6 +239,12 @@ module Async
|
|
238
239
|
attr_accessor :head
|
239
240
|
attr_accessor :tail
|
240
241
|
|
242
|
+
# @returns [String] A string representation of the node.
|
243
|
+
def to_s
|
244
|
+
sprintf("#<%s:0x%x>", self.class.name, object_id)
|
245
|
+
end
|
246
|
+
|
247
|
+
# @returns [String] A string representation of the node.
|
241
248
|
alias inspect to_s
|
242
249
|
end
|
243
250
|
|
data/lib/async/node.rb
CHANGED
data/lib/async/notification.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2025, by Samuel Williams.
|
5
5
|
|
6
6
|
require_relative "condition"
|
7
7
|
|
@@ -10,12 +10,14 @@ module Async
|
|
10
10
|
# @public Since *Async v1*.
|
11
11
|
class Notification < Condition
|
12
12
|
# Signal to a given task that it should resume operations.
|
13
|
+
#
|
14
|
+
# @returns [Boolean] if a task was signalled.
|
13
15
|
def signal(value = nil, task: Task.current)
|
14
|
-
return if @waiting.empty?
|
16
|
+
return false if @waiting.empty?
|
15
17
|
|
16
18
|
Fiber.scheduler.push Signal.new(self.exchange, value)
|
17
19
|
|
18
|
-
return
|
20
|
+
return true
|
19
21
|
end
|
20
22
|
|
21
23
|
Signal = Struct.new(:waiting, :value) do
|
data/lib/async/queue.rb
CHANGED
@@ -15,16 +15,31 @@ module Async
|
|
15
15
|
#
|
16
16
|
# @public Since *Async v1*.
|
17
17
|
class Queue
|
18
|
+
# An error raised when trying to enqueue items to a closed queue.
|
19
|
+
# @public Since *Async v2.24*.
|
20
|
+
class ClosedError < RuntimeError
|
21
|
+
end
|
22
|
+
|
18
23
|
# Create a new queue.
|
19
24
|
#
|
20
25
|
# @parameter parent [Interface(:async) | Nil] The parent task to use for async operations.
|
21
26
|
# @parameter available [Notification] The notification to use for signaling when items are available.
|
22
27
|
def initialize(parent: nil, available: Notification.new)
|
23
28
|
@items = []
|
29
|
+
@closed = false
|
24
30
|
@parent = parent
|
25
31
|
@available = available
|
26
32
|
end
|
27
33
|
|
34
|
+
# Close the queue, causing all waiting tasks to return `nil`. Any subsequent calls to {enqueue} will raise an exception.
|
35
|
+
def close
|
36
|
+
@closed = true
|
37
|
+
|
38
|
+
while @available.waiting?
|
39
|
+
@available.signal(nil)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
28
43
|
# @attribute [Array] The items in the queue.
|
29
44
|
attr :items
|
30
45
|
|
@@ -40,6 +55,10 @@ module Async
|
|
40
55
|
|
41
56
|
# Add an item to the queue.
|
42
57
|
def push(item)
|
58
|
+
if @closed
|
59
|
+
raise ClosedError, "Cannot push items to a closed queue."
|
60
|
+
end
|
61
|
+
|
43
62
|
@items << item
|
44
63
|
|
45
64
|
@available.signal unless self.empty?
|
@@ -52,6 +71,10 @@ module Async
|
|
52
71
|
|
53
72
|
# Add multiple items to the queue.
|
54
73
|
def enqueue(*items)
|
74
|
+
if @closed
|
75
|
+
raise ClosedError, "Cannot enqueue items to a closed queue."
|
76
|
+
end
|
77
|
+
|
55
78
|
@items.concat(items)
|
56
79
|
|
57
80
|
@available.signal unless self.empty?
|
@@ -60,6 +83,10 @@ module Async
|
|
60
83
|
# Remove and return the next item from the queue.
|
61
84
|
def dequeue
|
62
85
|
while @items.empty?
|
86
|
+
if @closed
|
87
|
+
return nil
|
88
|
+
end
|
89
|
+
|
63
90
|
@available.wait
|
64
91
|
end
|
65
92
|
|
@@ -106,6 +133,13 @@ module Async
|
|
106
133
|
# A queue which limits the number of items that can be enqueued.
|
107
134
|
# @public Since *Async v1*.
|
108
135
|
class LimitedQueue < Queue
|
136
|
+
# @private This exists purely for emitting a warning.
|
137
|
+
def self.new(...)
|
138
|
+
warn("`require 'async/limited_queue'` to use `Async::LimitedQueue`.", uplevel: 1, category: :deprecated) if $VERBOSE
|
139
|
+
|
140
|
+
super
|
141
|
+
end
|
142
|
+
|
109
143
|
# Create a new limited queue.
|
110
144
|
#
|
111
145
|
# @parameter limit [Integer] The maximum number of items that can be enqueued.
|
@@ -120,9 +154,19 @@ module Async
|
|
120
154
|
# @attribute [Integer] The maximum number of items that can be enqueued.
|
121
155
|
attr :limit
|
122
156
|
|
157
|
+
# Close the queue, causing all waiting tasks to return `nil`. Any subsequent calls to {enqueue} will raise an exception.
|
158
|
+
# Also signals all tasks waiting for the queue to be full.
|
159
|
+
def close
|
160
|
+
super
|
161
|
+
|
162
|
+
while @full.waiting?
|
163
|
+
@full.signal(nil)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
123
167
|
# @returns [Boolean] Whether trying to enqueue an item would block.
|
124
168
|
def limited?
|
125
|
-
@items.size >= @limit
|
169
|
+
!@closed && @items.size >= @limit
|
126
170
|
end
|
127
171
|
|
128
172
|
# Add an item to the queue.
|
@@ -149,6 +193,10 @@ module Async
|
|
149
193
|
@full.wait
|
150
194
|
end
|
151
195
|
|
196
|
+
if @closed
|
197
|
+
raise ClosedError, "Cannot enqueue items to a closed queue."
|
198
|
+
end
|
199
|
+
|
152
200
|
available = @limit - @items.size
|
153
201
|
@items.concat(items.shift(available))
|
154
202
|
|
data/lib/async/reactor.rb
CHANGED
data/lib/async/scheduler.rb
CHANGED
@@ -420,6 +420,9 @@ module Async
|
|
420
420
|
# @asynchronous May be non-blocking.
|
421
421
|
def io_select(...)
|
422
422
|
Thread.new do
|
423
|
+
# Don't make unnecessary output, since we will propagate the exception:
|
424
|
+
Thread.current.report_on_exception = false
|
425
|
+
|
423
426
|
::IO.select(...)
|
424
427
|
end.value
|
425
428
|
end
|
@@ -580,7 +583,7 @@ module Async
|
|
580
583
|
# @yields {|task| ...} Executed within the task.
|
581
584
|
# @returns [Task] The task that was scheduled into the reactor.
|
582
585
|
def async(*arguments, **options, &block)
|
583
|
-
|
586
|
+
warn("Async::Scheduler#async is deprecated. Use `run` or `Task#async` instead.", uplevel: 1, category: :deprecated) if $VERBOSE
|
584
587
|
|
585
588
|
Kernel.raise ClosedError if @selector.nil?
|
586
589
|
|
@@ -591,6 +594,8 @@ module Async
|
|
591
594
|
return task
|
592
595
|
end
|
593
596
|
|
597
|
+
# Create a new fiber and return it without starting execution.
|
598
|
+
# @returns [Fiber] The fiber that was created.
|
594
599
|
def fiber(...)
|
595
600
|
return async(...).fiber
|
596
601
|
end
|
data/lib/async/task.rb
CHANGED
@@ -65,6 +65,8 @@ module Async
|
|
65
65
|
|
66
66
|
# @deprecated With no replacement.
|
67
67
|
def self.yield
|
68
|
+
warn("`Async::Task.yield` is deprecated with no replacement.", uplevel: 1, category: :deprecated) if $VERBOSE
|
69
|
+
|
68
70
|
Fiber.scheduler.transfer
|
69
71
|
end
|
70
72
|
|
@@ -134,6 +136,8 @@ module Async
|
|
134
136
|
|
135
137
|
# @deprecated Prefer {Kernel#sleep} except when compatibility with `stable-v1` is required.
|
136
138
|
def sleep(duration = nil)
|
139
|
+
Kernel.warn("`Async::Task#sleep` is deprecated, use `Kernel#sleep` instead.", uplevel: 1, category: :deprecated) if $VERBOSE
|
140
|
+
|
137
141
|
super
|
138
142
|
end
|
139
143
|
|
data/lib/async/version.rb
CHANGED
data/lib/async/waiter.rb
CHANGED
@@ -6,12 +6,15 @@
|
|
6
6
|
|
7
7
|
module Async
|
8
8
|
# 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}.
|
9
|
+
# @deprecated `Async::Waiter` is deprecated, use `Async::Barrier` instead.
|
9
10
|
class Waiter
|
10
11
|
# Create a waiter instance.
|
11
12
|
#
|
12
13
|
# @parameter parent [Interface(:async) | Nil] The parent task to use for asynchronous operations.
|
13
14
|
# @parameter finished [Async::Condition] The condition to signal when a task completes.
|
14
15
|
def initialize(parent: nil, finished: Async::Condition.new)
|
16
|
+
warn("`Async::Waiter` is deprecated, use `Async::Barrier` instead.", uplevel: 1, category: :deprecated) if $VERBOSE
|
17
|
+
|
15
18
|
@finished = finished
|
16
19
|
@done = []
|
17
20
|
|
data/readme.md
CHANGED
@@ -35,6 +35,17 @@ 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.26.0
|
39
|
+
|
40
|
+
- `Async::Notification#signal` now returns `true` if a task was signaled, `false` otherwise, providing better feedback for notification operations.
|
41
|
+
- `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.
|
42
|
+
- `Async::Task#sleep` is deprecated with no replacement.
|
43
|
+
- `Async::Task.yield` is deprecated with no replacement.
|
44
|
+
- `Async::Scheduler#async` is deprecated, use `Async{}`, `Sync{}` or `Async::Task#async` instead.
|
45
|
+
- Agent context is now available, via the [`agent-context` gem](https://github.com/ioquatix/agent-context).
|
46
|
+
- [`Async::Barrier` Improvements](https://socketry.github.io/async/releases/index#async::barrier-improvements)
|
47
|
+
- [Introduce `Async::Queue#close`](https://socketry.github.io/async/releases/index#introduce-async::queue#close)
|
48
|
+
|
38
49
|
### v2.25.0
|
39
50
|
|
40
51
|
- 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.
|
@@ -62,7 +73,7 @@ Please see the [project releases](https://socketry.github.io/async/releases/inde
|
|
62
73
|
|
63
74
|
### v2.19.0
|
64
75
|
|
65
|
-
- [Async::Scheduler Debugging](https://socketry.github.io/async/releases/index#async::scheduler-debugging)
|
76
|
+
- [`Async::Scheduler` Debugging](https://socketry.github.io/async/releases/index#async::scheduler-debugging)
|
66
77
|
- [Console Shims](https://socketry.github.io/async/releases/index#console-shims)
|
67
78
|
|
68
79
|
### v2.18.0
|
data/releases.md
CHANGED
@@ -1,5 +1,87 @@
|
|
1
1
|
# Releases
|
2
2
|
|
3
|
+
## v2.26.0
|
4
|
+
|
5
|
+
- `Async::Notification#signal` now returns `true` if a task was signaled, `false` otherwise, providing better feedback for notification operations.
|
6
|
+
- `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.
|
7
|
+
- `Async::Task#sleep` is deprecated with no replacement.
|
8
|
+
- `Async::Task.yield` is deprecated with no replacement.
|
9
|
+
- `Async::Scheduler#async` is deprecated, use `Async{}`, `Sync{}` or `Async::Task#async` instead.
|
10
|
+
- Agent context is now available, via the [`agent-context` gem](https://github.com/ioquatix/agent-context).
|
11
|
+
|
12
|
+
### `Async::Barrier` Improvements
|
13
|
+
|
14
|
+
`Async::Barrier` now provides more flexible and predictable behavior for waiting on task completion:
|
15
|
+
|
16
|
+
- **Completion-order waiting**: `barrier.wait` now processes tasks in the order they complete rather than the order they were created. This provides more predictable behavior when tasks have different execution times.
|
17
|
+
- **Block-based waiting**: `barrier.wait` now accepts an optional block that yields each task as it completes, allowing for custom handling of individual tasks:
|
18
|
+
|
19
|
+
<!-- end list -->
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
barrier = Async::Barrier.new
|
23
|
+
|
24
|
+
# Start several tasks
|
25
|
+
3.times do |i|
|
26
|
+
barrier.async do |task|
|
27
|
+
sleep(rand * 0.1) # Random completion time
|
28
|
+
"result_#{i}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Wait for all tasks, processing them as they complete
|
33
|
+
barrier.wait do |task|
|
34
|
+
result = task.wait
|
35
|
+
puts "Task completed with: #{result}"
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
- **Partial completion support**: The new block-based interface allows you to wait for only the first N tasks to complete:
|
40
|
+
|
41
|
+
<!-- end list -->
|
42
|
+
|
43
|
+
``` ruby
|
44
|
+
# Wait for only the first 3 tasks to complete
|
45
|
+
count = 0
|
46
|
+
barrier.wait do |task|
|
47
|
+
task.wait
|
48
|
+
count += 1
|
49
|
+
break if count >= 3
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
This makes `Async::Barrier` a superset of `Async::Waiter` functionality, providing more flexible task coordination patterns, and therrefore, `Async::Waiter` is now deprecated.
|
54
|
+
|
55
|
+
### Introduce `Async::Queue#close`
|
56
|
+
|
57
|
+
`Async::Queue` and `Async::LimitedQueue` can now be closed, which provides better resource management and error handling:
|
58
|
+
|
59
|
+
- **New `close` method**: Both queue types now have a `close` method that prevents further items from being added and signals any waiting tasks.
|
60
|
+
- **Consistent error handling**: All queue modification methods (`push`, `enqueue`, `<<`) now raise `Async::Queue::ClosedError` when called on a closed queue.
|
61
|
+
- **Waiting task signaling**: When a queue is closed, any tasks waiting on `dequeue` (for regular queues) or `enqueue` (for limited queues) are properly signaled and can complete.
|
62
|
+
|
63
|
+
<!-- end list -->
|
64
|
+
|
65
|
+
``` ruby
|
66
|
+
queue = Async::Queue.new
|
67
|
+
|
68
|
+
# Start a task waiting for items:
|
69
|
+
waiting_task = Async do
|
70
|
+
queue.dequeue
|
71
|
+
end
|
72
|
+
|
73
|
+
# Close the queue - this signals the waiting task
|
74
|
+
queue.close
|
75
|
+
|
76
|
+
# These will raise Async::Queue::ClosedError
|
77
|
+
queue.push(:item) # => raises ClosedError
|
78
|
+
queue.enqueue(:item) # => raises ClosedError
|
79
|
+
queue << :item # => raises ClosedError
|
80
|
+
|
81
|
+
# Dequeue returns nil when closed and empty
|
82
|
+
queue.dequeue # => nil
|
83
|
+
```
|
84
|
+
|
3
85
|
## v2.25.0
|
4
86
|
|
5
87
|
- 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.
|
@@ -34,7 +116,7 @@ end
|
|
34
116
|
|
35
117
|
### Flexible Timeouts
|
36
118
|
|
37
|
-
When
|
119
|
+
When `Async::Scheduler#with_timeout` is invoked with a block, it can receive a `Async::Timeout` instance. This allows you to adjust or cancel the timeout while the block is executing. This is useful for long-running tasks that may need to adjust their timeout based on external factors.
|
38
120
|
|
39
121
|
``` ruby
|
40
122
|
Async do
|
@@ -108,7 +190,7 @@ To take advantage of this feature, you will need to introduce your own `config/t
|
|
108
190
|
|
109
191
|
## v2.19.0
|
110
192
|
|
111
|
-
### Async::Scheduler Debugging
|
193
|
+
### `Async::Scheduler` Debugging
|
112
194
|
|
113
195
|
Occasionally on issues, I encounter people asking for help and I need more information. Pressing Ctrl-C to exit a hung program is common, but it usually doesn't provide enough information to diagnose the problem. Setting the `CONSOLE_LEVEL=debug` environment variable will now print additional information about the scheduler when you interrupt it, including a backtrace of the current tasks.
|
114
196
|
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.26.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -10,6 +10,7 @@ authors:
|
|
10
10
|
- Olle Jonsson
|
11
11
|
- Patrik Wenger
|
12
12
|
- Devin Christensen
|
13
|
+
- Shopify Inc.
|
13
14
|
- Emil Tin
|
14
15
|
- Jamie McCarthy
|
15
16
|
- Kent Gruber
|
@@ -32,7 +33,6 @@ authors:
|
|
32
33
|
- Salim Semaoune
|
33
34
|
- Shannon Skipper
|
34
35
|
- Shigeru Nakajima
|
35
|
-
- Shopify Inc.
|
36
36
|
- Sokolov Yura
|
37
37
|
- Stefan Wrobel
|
38
38
|
- Trevor Turk
|
@@ -103,14 +103,14 @@ dependencies:
|
|
103
103
|
requirements:
|
104
104
|
- - "~>"
|
105
105
|
- !ruby/object:Gem::Version
|
106
|
-
version: '1.
|
106
|
+
version: '1.12'
|
107
107
|
type: :runtime
|
108
108
|
prerelease: false
|
109
109
|
version_requirements: !ruby/object:Gem::Requirement
|
110
110
|
requirements:
|
111
111
|
- - "~>"
|
112
112
|
- !ruby/object:Gem::Version
|
113
|
-
version: '1.
|
113
|
+
version: '1.12'
|
114
114
|
- !ruby/object:Gem::Dependency
|
115
115
|
name: metrics
|
116
116
|
requirement: !ruby/object:Gem::Requirement
|
@@ -143,6 +143,7 @@ executables: []
|
|
143
143
|
extensions: []
|
144
144
|
extra_rdoc_files: []
|
145
145
|
files:
|
146
|
+
- agent.md
|
146
147
|
- lib/async.rb
|
147
148
|
- lib/async/barrier.md
|
148
149
|
- lib/async/barrier.rb
|
@@ -165,7 +166,6 @@ files:
|
|
165
166
|
- lib/async/timeout.rb
|
166
167
|
- lib/async/variable.rb
|
167
168
|
- lib/async/version.rb
|
168
|
-
- lib/async/waiter.md
|
169
169
|
- lib/async/waiter.rb
|
170
170
|
- lib/kernel/async.rb
|
171
171
|
- lib/kernel/sync.rb
|
metadata.gz.sig
CHANGED
Binary file
|
data/lib/async/waiter.md
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
A synchronization primitive, which allows you to wait for tasks to complete in order of completion. This is useful for implementing a task pool, where you want to wait for the first task to complete, and then cancel the rest.
|
2
|
-
|
3
|
-
If you try to wait for more things than you have added, you will deadlock.
|
4
|
-
|
5
|
-
## Example
|
6
|
-
|
7
|
-
~~~ ruby
|
8
|
-
require 'async'
|
9
|
-
require 'async/semaphore'
|
10
|
-
require 'async/barrier'
|
11
|
-
require 'async/waiter'
|
12
|
-
|
13
|
-
Sync do
|
14
|
-
barrier = Async::Barrier.new
|
15
|
-
waiter = Async::Waiter.new(parent: barrier)
|
16
|
-
semaphore = Async::Semaphore.new(2, parent: waiter)
|
17
|
-
|
18
|
-
# Sleep sort the numbers:
|
19
|
-
generator = Async do
|
20
|
-
while true
|
21
|
-
semaphore.async do |task|
|
22
|
-
number = rand(1..10)
|
23
|
-
sleep(number)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
numbers = []
|
29
|
-
|
30
|
-
4.times do
|
31
|
-
# Wait for all the numbers to be sorted:
|
32
|
-
numbers << waiter.wait
|
33
|
-
end
|
34
|
-
|
35
|
-
# Don't generate any more numbers:
|
36
|
-
generator.stop
|
37
|
-
|
38
|
-
# Stop all tasks which we don't care about:
|
39
|
-
barrier.stop
|
40
|
-
|
41
|
-
Console.info("Smallest", numbers)
|
42
|
-
end
|
43
|
-
~~~
|
44
|
-
|
45
|
-
### Output
|
46
|
-
|
47
|
-
~~~
|
48
|
-
0.0s info: Smallest
|
49
|
-
| [3, 3, 1, 2]
|
50
|
-
~~~
|