-
Notifications
You must be signed in to change notification settings - Fork 0
Error Handling
FiberLoops fails loudly and predictably. There are two things to understand: the one exception the package itself throws, and how exceptions from your tasks behave. All examples assume:
require_once 'vendor/autoload.php';
use InitPHP\FiberLoops\Loop;
use InitPHP\FiberLoops\Exception\LoopException;namespace InitPHP\FiberLoops\Exception;
class LoopException extends \RuntimeExceptionLoopException is thrown when the loop is driven in a way its cooperative model
does not allow. In practice that means one thing: calling next() or
sleep() from outside a fiber. It extends \RuntimeException, so you can catch it
as LoopException, RuntimeException, or Throwable.
next() and sleep() suspend the current fiber, which is only legal inside a
fiber. Call them from the main script and you get a LoopException with a message
that tells you exactly what to do:
$loop = new Loop();
try {
$loop->next(); // not inside a task
} catch (LoopException $e) {
echo $e->getMessage() . "\n";
}Loop::next() must be called from within a fiber, e.g. inside a task passed to Loop::defer() or Loop::await().
The same applies to sleep() with a positive duration (it yields via next()):
$loop = new Loop();
try {
$loop->sleep(0.1); // not inside a task
} catch (LoopException $e) {
echo "caught: " . get_class($e) . "\n";
}caught: InitPHP\FiberLoops\Exception\LoopException
Without this guard, PHP would surface a bare
FiberError: Cannot suspend outside of a fiber.LoopExceptionwraps that precondition in a package-namespaced type with an actionable message. (Note:sleep(0)is a no-op that never yields, so it does not throw even outside a fiber.)
Only call next() / sleep() from inside a task:
$loop = new Loop();
$loop->defer(function () use ($loop) {
$loop->sleep(0.1); // fine — we are inside a fiber here
echo "done\n";
});
$loop->run();done
A task is a fiber. An uncaught exception thrown inside a task surfaces where the
fiber is being driven — that is, out of run() (or out of await() if you are
awaiting the task). The loop does not swallow it:
$loop = new Loop();
$loop->defer(function () {
throw new \RuntimeException('boom');
});
try {
$loop->run();
} catch (\RuntimeException $e) {
echo "propagated out of run(): " . $e->getMessage() . "\n";
}propagated out of run(): boom
If you want the loop to survive a failing task, wrap the risky work in a
try/catch inside the task. The other tasks then run unaffected:
$loop = new Loop();
$loop->defer(function () {
try {
throw new \RuntimeException('boom');
} catch (\RuntimeException $e) {
echo "task handled: {$e->getMessage()}\n";
}
});
$loop->defer(function () {
echo "other task ran fine\n";
});
$loop->run();task handled: boom
other task ran fine
One failing task can stop the loop. Because an uncaught exception breaks out of
run(), tasks queued after the failing one on that pass may not run. If a task does work that can fail and you want isolation, catch inside the task.
| Situation | What happens |
|---|---|
next() / sleep(> 0) outside a fiber |
LoopException thrown |
sleep(0) outside a fiber |
No-op, no exception |
| Uncaught exception inside a task | Propagates out of run() / await()
|
| Exception caught inside the task | Loop continues normally |
- Yielding & Sleeping — the methods that require a fiber.
- Troubleshooting — symptoms and fixes.
- API Reference — the exception class.
Getting Started
Using FiberLoops
Guides
Reference