Menu
Reference
- Manticore\Ds
- Async
- Classes
- AggregateError
- CancellationToken
- CancelledException
- Channel
- ChannelClosedException
- Context
- DeadlockException
- Mutex
- Once
- Pool
- Received
- SelectCase
- Selected
- Semaphore
- Settled
- Task
- TaskGroup
- TimeoutException
- Functions
- async()
- awaitAll()
- awaitAllSettled()
- awaitAny()
- channel()
- delay()
- dump()
- dumpOn()
- failure()
- group()
- mapConcurrent()
- mapSettled()
- readFile()
- select()
- selectNow()
- selectWithin()
- shield()
- shutdownOn()
- spawn()
- stats()
- timeout()
- watchdog()
- writeFile()
- Http
- Http\WebSocket
- Buffer
- Process
- Io\Poll
- Manticore\Sapi
- Ffi
CancelledException
finalclass
final class CancelledException extends \Error
Raised inside a task that was cancelled.
Cancellation is delivered at the task's current suspend point (a delay(), a channel wait, a blocking stream call, an await()) and is sticky: it is raised again at every later suspend point until the task ends. Catching it once therefore buys a task one more suspend, not immunity. Let it propagate, or run cleanup that must itself suspend inside shield().
It extends \Error, not \Exception, on purpose: the blanket catch (\Exception $e) most PHP code is written with cannot swallow it. A scope that cancelled its own children does not count their CancelledException as a failure.
try {
delay(10.0);
} catch (CancelledException $e) {
shield(fn() => $conn->close()); // cleanup that suspends
throw $e; // always rethrow
}Example
use Async\CancelledException;
use Async\TaskGroup;
use function Async\async;
use function Async\delay;
use function Async\group;
async(function () {
group(function (TaskGroup $g) {
$token = $g->token();
$token->onCancel(fn() => print("onCancel hook ran\n"));
// A task that suspends is interrupted with CancelledException,
// which extends \Error: catch (\Exception) cannot swallow it.
$g->spawn(function () {
try {
delay(10.0);
} catch (CancelledException $e) {
echo "sleeper cancelled\n";
throw $e;
}
});
// A loop that never suspends polls the token instead.
$g->spawn(function () use ($g, $token) {
for ($step = 1; $step <= 5; $step++) {
if ($step === 3) {
$g->cancel(); // the write half; $token is the read-only view
}
if ($token->isCancelled()) {
echo "loop stopped at step $step\n";
return;
}
echo "step $step\n";
}
});
});
echo "scope joined\n";
});Output
step 1
step 2
onCancel hook ran
loop stopped at step 3
sleeper cancelled
scope joinedSee also: shield, Task::cancel, TaskGroup::cancel, CancellationToken