async 2.14.2 → 2.15.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/async/condition.rb +1 -1
- data/lib/async/idler.rb +2 -1
- data/lib/async/list.rb +1 -1
- data/lib/async/node.rb +27 -1
- data/lib/async/notification.rb +1 -1
- data/lib/async/queue.rb +1 -1
- data/lib/async/reactor.rb +1 -1
- data/lib/async/scheduler.rb +57 -45
- data/lib/async/task.rb +7 -4
- data/lib/async/variable.rb +1 -1
- data/lib/async/version.rb +1 -1
- data/lib/async/waiter.rb +2 -1
- data/lib/async/wrapper.rb +1 -1
- data/lib/async.rb +1 -1
- data/license.md +2 -1
- data/readme.md +3 -3
- data.tar.gz.sig +0 -0
- metadata +7 -12
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d69239cbc022fd8b50e28bac6356f037ae0ff221605f9309312b1b8566b61ac1
|
4
|
+
data.tar.gz: ba47d3b3f2d50e4999eb219338ab9e3d619882c9b3de3b000c07a6f2dca89d21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ddd53973722c47e13f92c93149cdc5a111af55af22a9d810aaddbe29fe6b996937737b929556dec48c22deab204d8113574892bb6f2095e991aea62a9188529
|
7
|
+
data.tar.gz: 2c2c81505e97ebe5fe28fde6abe3eeed7641f5f6e4ead801432c31b60e85d378a6b823bcd97903d11cbfdd3f937f40e80ee288f0e6fb2c961884358c0d30c905
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/async/condition.rb
CHANGED
data/lib/async/idler.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, by Samuel Williams.
|
4
|
+
# Copyright, 2022-2024, 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.
|
data/lib/async/node.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2017-
|
4
|
+
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2017, by Kent Gruber.
|
6
6
|
# Copyright, 2022, by Shannon Skipper.
|
7
7
|
|
@@ -34,6 +34,19 @@ module Async
|
|
34
34
|
empty?
|
35
35
|
end
|
36
36
|
|
37
|
+
# Adjust the number of transient children, assuming it has changed.
|
38
|
+
#
|
39
|
+
# Despite being public, this is not intended to be called directly. It is used internally by {Node#transient=}.
|
40
|
+
#
|
41
|
+
# @parameter transient [Boolean] Whether to increment or decrement the transient count.
|
42
|
+
def adjust_transient_count(transient)
|
43
|
+
if transient
|
44
|
+
@transient_count += 1
|
45
|
+
else
|
46
|
+
@transient_count -= 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
37
50
|
private
|
38
51
|
|
39
52
|
def added(node)
|
@@ -110,6 +123,19 @@ module Async
|
|
110
123
|
@transient
|
111
124
|
end
|
112
125
|
|
126
|
+
# Change the transient state of the node.
|
127
|
+
#
|
128
|
+
# A transient node is not considered when determining if a node is finished, and propagates up if the parent is consumed.
|
129
|
+
#
|
130
|
+
# @parameter value [Boolean] Whether the node is transient.
|
131
|
+
def transient=(value)
|
132
|
+
if @transient != value
|
133
|
+
@transient = value
|
134
|
+
|
135
|
+
@parent&.children&.adjust_transient_count(value)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
113
139
|
# Annotate the node with a description.
|
114
140
|
#
|
115
141
|
# @parameter annotation [String] The description to annotate the node with.
|
data/lib/async/notification.rb
CHANGED
data/lib/async/queue.rb
CHANGED
data/lib/async/reactor.rb
CHANGED
data/lib/async/scheduler.rb
CHANGED
@@ -71,47 +71,46 @@ module Async
|
|
71
71
|
return @busy_time / total_time
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
# Invoked when the fiber scheduler is being closed.
|
76
76
|
#
|
77
77
|
# Executes the run loop until all tasks are finished, then closes the scheduler.
|
78
|
-
def scheduler_close
|
78
|
+
def scheduler_close(error = $!)
|
79
79
|
# If the execution context (thread) was handling an exception, we want to exit as quickly as possible:
|
80
|
-
unless
|
80
|
+
unless error
|
81
81
|
self.run
|
82
82
|
end
|
83
83
|
ensure
|
84
84
|
self.close
|
85
85
|
end
|
86
86
|
|
87
|
-
# Terminate
|
87
|
+
# Terminate all child tasks.
|
88
88
|
def terminate
|
89
|
-
|
90
|
-
|
89
|
+
# If that doesn't work, take more serious action:
|
90
|
+
@children&.each do |child|
|
91
|
+
child.terminate
|
91
92
|
end
|
93
|
+
|
94
|
+
return @children.nil?
|
92
95
|
end
|
93
96
|
|
94
97
|
# Terminate all child tasks and close the scheduler.
|
95
98
|
# @public Since `stable-v1`.
|
96
99
|
def close
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
+
self.run_loop do
|
101
|
+
until self.terminate
|
102
|
+
self.run_once!
|
103
|
+
end
|
100
104
|
end
|
101
105
|
|
102
106
|
Kernel.raise "Closing scheduler with blocked operations!" if @blocked > 0
|
103
|
-
|
104
|
-
# We depend on GVL for consistency:
|
105
|
-
# @guard.synchronize do
|
106
|
-
|
107
|
+
ensure
|
107
108
|
# We want `@selector = nil` to be a visible side effect from this point forward, specifically in `#interrupt` and `#unblock`. If the selector is closed, then we don't want to push any fibers to it.
|
108
109
|
selector = @selector
|
109
110
|
@selector = nil
|
110
111
|
|
111
112
|
selector&.close
|
112
113
|
|
113
|
-
# end
|
114
|
-
|
115
114
|
consume
|
116
115
|
end
|
117
116
|
|
@@ -292,28 +291,13 @@ module Async
|
|
292
291
|
return @selector.process_wait(Fiber.current, pid, flags)
|
293
292
|
end
|
294
293
|
|
295
|
-
# Run one iteration of the event loop.
|
296
|
-
# Does not handle interrupts.
|
297
|
-
# @parameter timeout [Float | Nil] The maximum timeout, or if nil, indefinite.
|
298
|
-
# @returns [Boolean] Whether there is more work to do.
|
299
|
-
def run_once(timeout = nil)
|
300
|
-
Kernel::raise "Running scheduler on non-blocking fiber!" unless Fiber.blocking?
|
301
|
-
|
302
|
-
# If we are finished, we stop the task tree and exit:
|
303
|
-
if self.finished?
|
304
|
-
return false
|
305
|
-
end
|
306
|
-
|
307
|
-
return run_once!(timeout)
|
308
|
-
end
|
309
|
-
|
310
294
|
# Run one iteration of the event loop.
|
311
295
|
#
|
312
296
|
# When terminating the event loop, we already know we are finished. So we don't need to check the task tree. This is a logical requirement because `run_once` ignores transient tasks. For example, a single top level transient task is not enough to keep the reactor running, but during termination we must still process it in order to terminate child tasks.
|
313
297
|
#
|
314
298
|
# @parameter timeout [Float | Nil] The maximum timeout, or if nil, indefinite.
|
315
299
|
# @returns [Boolean] Whether there is more work to do.
|
316
|
-
private def run_once!(timeout =
|
300
|
+
private def run_once!(timeout = nil)
|
317
301
|
start_time = Async::Clock.now
|
318
302
|
|
319
303
|
interval = @timers.wait_interval
|
@@ -350,6 +334,25 @@ module Async
|
|
350
334
|
return true
|
351
335
|
end
|
352
336
|
|
337
|
+
# Run one iteration of the event loop.
|
338
|
+
# Does not handle interrupts.
|
339
|
+
# @parameter timeout [Float | Nil] The maximum timeout, or if nil, indefinite.
|
340
|
+
# @returns [Boolean] Whether there is more work to do.
|
341
|
+
def run_once(timeout = nil)
|
342
|
+
Kernel.raise "Running scheduler on non-blocking fiber!" unless Fiber.blocking?
|
343
|
+
|
344
|
+
if self.finished?
|
345
|
+
self.stop
|
346
|
+
end
|
347
|
+
|
348
|
+
# If we are finished, we stop the task tree and exit:
|
349
|
+
if @children.nil?
|
350
|
+
return false
|
351
|
+
end
|
352
|
+
|
353
|
+
return run_once!(timeout)
|
354
|
+
end
|
355
|
+
|
353
356
|
# Checks and clears the interrupted state of the scheduler.
|
354
357
|
# @returns [Boolean] Whether the reactor has been interrupted.
|
355
358
|
private def interrupted?
|
@@ -365,22 +368,22 @@ module Async
|
|
365
368
|
return false
|
366
369
|
end
|
367
370
|
|
368
|
-
#
|
369
|
-
def
|
370
|
-
|
371
|
-
|
372
|
-
|
371
|
+
# Stop all children, including transient children, ignoring any signals.
|
372
|
+
def stop
|
373
|
+
@children&.each do |child|
|
374
|
+
child.stop
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
private def run_loop(&block)
|
373
379
|
interrupt = nil
|
374
380
|
|
375
381
|
begin
|
376
382
|
# In theory, we could use Exception here to be a little bit safer, but we've only shown the case for SignalException to be a problem, so let's not over-engineer this.
|
377
383
|
Thread.handle_interrupt(::SignalException => :never) do
|
378
|
-
|
379
|
-
# If we are interrupted, we need to exit:
|
380
|
-
break if self.interrupted?
|
381
|
-
|
384
|
+
until self.interrupted?
|
382
385
|
# If we are finished, we need to exit:
|
383
|
-
break unless
|
386
|
+
break unless yield
|
384
387
|
end
|
385
388
|
end
|
386
389
|
rescue Interrupt => interrupt
|
@@ -392,11 +395,20 @@ module Async
|
|
392
395
|
end
|
393
396
|
|
394
397
|
# If the event loop was interrupted, and we finished exiting normally (due to the interrupt), we need to re-raise the interrupt so that the caller can handle it too.
|
395
|
-
Kernel.raise
|
398
|
+
Kernel.raise(interrupt) if interrupt
|
399
|
+
end
|
400
|
+
|
401
|
+
# Run the reactor until all tasks are finished. Proxies arguments to {#async} immediately before entering the loop, if a block is provided.
|
402
|
+
def run(...)
|
403
|
+
Kernel.raise ClosedError if @selector.nil?
|
404
|
+
|
405
|
+
initial_task = self.async(...) if block_given?
|
406
|
+
|
407
|
+
self.run_loop do
|
408
|
+
run_once
|
409
|
+
end
|
396
410
|
|
397
411
|
return initial_task
|
398
|
-
ensure
|
399
|
-
Console.debug(self) {"Exiting run-loop because #{$! ? $! : 'finished'}."}
|
400
412
|
end
|
401
413
|
|
402
414
|
# Start an asynchronous task within the specified reactor. The task will be
|
@@ -409,7 +421,7 @@ module Async
|
|
409
421
|
# @returns [Task] The task that was scheduled into the reactor.
|
410
422
|
# @deprecated With no replacement.
|
411
423
|
def async(*arguments, **options, &block)
|
412
|
-
Kernel
|
424
|
+
Kernel.raise ClosedError if @selector.nil?
|
413
425
|
|
414
426
|
task = Task.new(Task.current? || self, **options, &block)
|
415
427
|
|
data/lib/async/task.rb
CHANGED
@@ -176,7 +176,7 @@ module Async
|
|
176
176
|
|
177
177
|
alias complete? completed?
|
178
178
|
|
179
|
-
# @attribute [Symbol] The status of the execution of the
|
179
|
+
# @attribute [Symbol] The status of the execution of the task, one of `:initialized`, `:running`, `:complete`, `:stopped` or `:failed`.
|
180
180
|
attr :status
|
181
181
|
|
182
182
|
# Begin the execution of the task.
|
@@ -192,8 +192,8 @@ module Async
|
|
192
192
|
# 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.
|
193
193
|
if @finished.nil?
|
194
194
|
Console::Event::Failure.for(error).emit(self, "Task may have ended with unhandled exception.", severity: :warn)
|
195
|
-
|
196
|
-
|
195
|
+
else
|
196
|
+
# Console::Event::Failure.for(error).emit(self, severity: :debug)
|
197
197
|
end
|
198
198
|
|
199
199
|
raise
|
@@ -262,6 +262,9 @@ module Async
|
|
262
262
|
|
263
263
|
# If the fiber is alive, we need to stop it:
|
264
264
|
if @fiber&.alive?
|
265
|
+
# As the task is now exiting, we want to ensure the event loop continues to execute until the task finishes.
|
266
|
+
self.transient = false
|
267
|
+
|
265
268
|
if self.current?
|
266
269
|
# If the fiber is current, and later is `true`, we need to schedule the fiber to be stopped later, as it's currently invoking `stop`:
|
267
270
|
if later
|
@@ -276,7 +279,7 @@ module Async
|
|
276
279
|
begin
|
277
280
|
# There is a chance that this will stop the fiber that originally called stop. If that happens, the exception handling in `#stopped` will rescue the exception and re-raise it later.
|
278
281
|
Fiber.scheduler.raise(@fiber, Stop)
|
279
|
-
rescue FiberError
|
282
|
+
rescue FiberError => error
|
280
283
|
# In some cases, this can cause a FiberError (it might be resumed already), so we schedule it to be stopped later:
|
281
284
|
Fiber.scheduler.push(Stop::Later.new(self))
|
282
285
|
end
|
data/lib/async/variable.rb
CHANGED
data/lib/async/version.rb
CHANGED
data/lib/async/waiter.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2022, by Samuel Williams.
|
4
|
+
# Copyright, 2022-2024, by Samuel Williams.
|
5
|
+
# Copyright, 2024, by Patrik Wenger.
|
5
6
|
|
6
7
|
module Async
|
7
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}.
|
data/lib/async/wrapper.rb
CHANGED
data/lib/async.rb
CHANGED
data/license.md
CHANGED
@@ -11,7 +11,7 @@ Copyright, 2020-2023, by Olle Jonsson.
|
|
11
11
|
Copyright, 2020, by Salim Semaoune.
|
12
12
|
Copyright, 2020, by Brian Morearty.
|
13
13
|
Copyright, 2020, by Stefan Wrobel.
|
14
|
-
Copyright, 2020, by Patrik Wenger.
|
14
|
+
Copyright, 2020-2024, by Patrik Wenger.
|
15
15
|
Copyright, 2020, by Ken Muryoi.
|
16
16
|
Copyright, 2020, by Jun Jiang.
|
17
17
|
Copyright, 2020-2022, by Bruno Sutic.
|
@@ -26,6 +26,7 @@ Copyright, 2023, by Math Ieu.
|
|
26
26
|
Copyright, 2023, by Emil Tin.
|
27
27
|
Copyright, 2023, by Gert Goet.
|
28
28
|
Copyright, 2024, by Dimitar Peychinov.
|
29
|
+
Copyright, 2024, by Jamie McCarthy.
|
29
30
|
|
30
31
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
31
32
|
of this software and associated documentation files (the "Software"), to deal
|
data/readme.md
CHANGED
@@ -43,11 +43,11 @@ We welcome contributions to this project.
|
|
43
43
|
|
44
44
|
### Developer Certificate of Origin
|
45
45
|
|
46
|
-
|
46
|
+
In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
|
47
47
|
|
48
|
-
###
|
48
|
+
### Community Guidelines
|
49
49
|
|
50
|
-
This project is
|
50
|
+
This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
|
51
51
|
|
52
52
|
## See Also
|
53
53
|
|
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.15.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -9,7 +9,9 @@ authors:
|
|
9
9
|
- Jeremy Jung
|
10
10
|
- Olle Jonsson
|
11
11
|
- Devin Christensen
|
12
|
+
- Patrik Wenger
|
12
13
|
- Emil Tin
|
14
|
+
- Jamie McCarthy
|
13
15
|
- Kent Gruber
|
14
16
|
- Brian Morearty
|
15
17
|
- Colin Kelley
|
@@ -23,7 +25,6 @@ authors:
|
|
23
25
|
- Masafumi Okura
|
24
26
|
- Masayuki Yamamoto
|
25
27
|
- Math Ieu
|
26
|
-
- Patrik Wenger
|
27
28
|
- Ryan Musgrave
|
28
29
|
- Salim Semaoune
|
29
30
|
- Shannon Skipper
|
@@ -62,7 +63,7 @@ cert_chain:
|
|
62
63
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
63
64
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
64
65
|
-----END CERTIFICATE-----
|
65
|
-
date: 2024-07
|
66
|
+
date: 2024-08-07 00:00:00.000000000 Z
|
66
67
|
dependencies:
|
67
68
|
- !ruby/object:Gem::Dependency
|
68
69
|
name: console
|
@@ -70,20 +71,14 @@ dependencies:
|
|
70
71
|
requirements:
|
71
72
|
- - "~>"
|
72
73
|
- !ruby/object:Gem::Version
|
73
|
-
version: '1.
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: 1.25.2
|
74
|
+
version: '1.26'
|
77
75
|
type: :runtime
|
78
76
|
prerelease: false
|
79
77
|
version_requirements: !ruby/object:Gem::Requirement
|
80
78
|
requirements:
|
81
79
|
- - "~>"
|
82
80
|
- !ruby/object:Gem::Version
|
83
|
-
version: '1.
|
84
|
-
- - ">="
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
version: 1.25.2
|
81
|
+
version: '1.26'
|
87
82
|
- !ruby/object:Gem::Dependency
|
88
83
|
name: fiber-annotation
|
89
84
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
167
|
- !ruby/object:Gem::Version
|
173
168
|
version: '0'
|
174
169
|
requirements: []
|
175
|
-
rubygems_version: 3.5.
|
170
|
+
rubygems_version: 3.5.13
|
176
171
|
signing_key:
|
177
172
|
specification_version: 4
|
178
173
|
summary: A concurrency framework for Ruby.
|
metadata.gz.sig
CHANGED
Binary file
|