Menu

Reference / Async

shield()

function
function shield(callable $body): mixed

Hold cancellation back while $body runs.

For cleanup that must itself suspend (a close handshake, a final flush). Without it a cancelled task could never release anything that needs I/O, because every suspend point re-raises CancelledException. A cancellation requested during or before the shield is delivered at the first suspend point after it ends. Keep it short: a shielded task cannot be stopped. Shields nest.

try {
    delay(30.0);
} catch (CancelledException $e) {
    shield(fn() => $conn->sendCloseFrame());
    throw $e;
}

Parameters

$body callable
the cleanup, called with no arguments

Returns

mixed — the value returned by $body

Throws

\Throwable
whatever $body throws

Example

use Async\CancelledException;
use function Async\async;
use function Async\delay;
use function Async\shield;
use function Async\spawn;

async(function () {
    $worker = spawn(function () {
        try {
            delay(10.0);
        } catch (CancelledException $e) {
            // Cancellation is re-raised at every suspend point, so cleanup
            // that itself suspends must be shielded.
            shield(function () {
                delay(0.01);
                echo "cleanup finished\n";
            });
            throw $e;
        }
    });

    delay(0.01);
    $worker->cancel();

    // join() reports how the task ended without rethrowing it here.
    $outcome = $worker->join();
    echo $outcome->ok ? "completed\n" : "ended with " . get_class($outcome->error) . "\n";
});

Output

cleanup finished
ended with Async\CancelledException

See also: CancelledException, Task::cancel

View source