TaskSet::joinAny
(PHP 8.6+, True Async 1.0)
public TaskSet::joinAny(): Async\Future
Returns a Future that resolves with the result of the first successfully completed task.
Tasks that finished with an error are skipped.
After delivering the result, the entry is automatically removed from the set.
Remaining tasks continue running.
If all tasks finished with errors, the Future rejects with CompositeException.
The returned Future supports a cancellation token via await(?Completable $cancellation).
Return Value
Async\Future — a future result of the first successful task.
Call ->await() to get the value.
Errors
- Throws
Async\AsyncExceptionif the set is empty. - The
Futurerejects withAsync\CompositeExceptionif all tasks finished with errors.
Examples
Example #1 First successful result
<?php
use Async\TaskSet;
spawn(function() {
$set = new TaskSet();
$set->spawn(fn() => throw new \RuntimeException("fail 1"));
$set->spawn(fn() => throw new \RuntimeException("fail 2"));
$set->spawn(fn() => "success!");
$result = $set->joinAny()->await();
echo $result . "\n"; // "success!"
echo $set->count() . "\n"; // 2 (failed tasks remain)
});
Example #2 All tasks failed
<?php
use Async\TaskSet;
spawn(function() {
$set = new TaskSet();
$set->spawn(fn() => throw new \RuntimeException("err 1"));
$set->spawn(fn() => throw new \RuntimeException("err 2"));
$set->seal();
try {
$set->joinAny()->await();
} catch (\Async\CompositeException $e) {
echo count($e->getExceptions()) . " errors\n"; // "2 errors"
}
});
Example #3 Resilient search
<?php
use Async\TaskSet;
spawn(function() {
$set = new TaskSet();
$set->spawn(fn() => searchGoogle($query));
$set->spawn(fn() => searchBing($query));
$set->spawn(fn() => searchDuckDuckGo($query));
$result = $set->joinAny()->await(Async\timeout(3.0));
echo "Found, active: {$set->count()}\n";
});
See Also
- TaskSet::joinNext — First completed (success or error)
- TaskSet::joinAll — All results
- TaskGroup::any — Equivalent without auto-cleanup