NAME
Punk::Future - an async result that runs on the loop, or blocks
SYNOPSIS
my $f = Punk::Future->new;
$f->on_done(sub { my @v = @_; ... });
$f->done({ ok => 1 });
# in a controller: resolve later, hand the future back
get '/slow' => sub {
my ($c) = @_;
$c->timer(2)->then(sub { $c->json({ waited => 2 }) });
};
DESCRIPTION
A Future-compatible asynchronous result. On a live Hyperman worker loop it is fully non-blocking: timers and continuations run on the loop and the worker serves other requests while it is pending. Anywhere else (another PSGI server, a script, the test suite) it degrades to blocking - a timer sleeps, and an unsettled get is an error, exactly as an off-loop Future is.
A handler may return one: Punk's dispatcher awaits any future-compatible value (it keys on then / on_ready / get), so returning a Punk::Future defers the response on the loop and awaits it inline off it.
CONSTRUCTORS
new
A new pending future.
done_future(@values) / fail_future(@failure)
An already-settled future.
RESOLVING
done(@values) / fail(@failure)
Settle a pending future; fires its callbacks. A no-op on an already-settled future. Chainable.
cancel
Settle a pending future cancelled; its on_ready callbacks and any then-chain fire, the chain propagating the cancellation onward. Chainable.
STATE
is_ready / is_done / is_failed / is_cancelled
state
Booleans, and the raw settle state.
failure
The first failure value of a failed future, or undef.
CALLBACKS
on_ready($cb)
$cb->($future) when it settles, any outcome.
on_done($cb) / on_fail($cb)
$cb->(@values) for the matching outcome. All three fire at once on an already-settled future and return the future.
on_cancel($code_or_future)
Given a coderef, $cb->($future) when this future is cancelled; given another future, cancel that one with it. Registering on a future already cancelled runs the target at once; on one that settled done or failed it is dropped, because that future will never cancel. Returns the future.
CHAINING
Each returns a new future the callback's result settles; a callback that returns a future is adopted, so chains compose without nesting.
then($on_done, $on_fail?)
Map the value on success (and, given $on_fail, recover a failure); otherwise the failure passes through.
else($on_fail) / catch($on_fail)
The failure branch only; a success passes through.
followed_by($cb)
$cb->($future) once it settles either way; adopt the future it returns.
AWAITING
get / result / await
get blocks until ready and returns the values (or rethrows the failure); result is the same method under Future's name for it; await blocks and returns the future. On a live loop they pump it; off-loop a pending future with nothing to settle it is an error (as an off-loop Future is).
In list context you get every value; in scalar context, the first, as Future gives you.
TIMERS
timer($secs)
A future that settles after $secs - a loop timer on a live worker, a plain sleep off it. Also $c->timer / $c->after.
defer($cb)
Run $cb on the next loop tick (or now, off-loop); the future settles with its result.
COMBINATORS
Each takes a list of futures and returns one.
needs_all(@futures) / all
Done when all succeed (their values combined in order); fails as soon as any fails.
needs_any(@futures) / any
Done on the first success; fails only if all fail.
wait_all(@futures)
Done when all have settled, whatever the outcome (the futures are the value).
wait_any(@futures)
Done as soon as any has settled.
ASYNC/AWAIT
This class implements the Future::AsyncAwait::Awaitable API, so one of these can be awaited directly. Punk::AsyncAwait is the one line that turns the keywords on in an app, controller or model:
use Punk::AsyncAwait;
async sub list {
my ($c) = @_;
my $page = await $c->model('Book')->search({});
return $c->render('book/list', { books => $page->{rows} });
}
Two things worth knowing. The future an async sub returns is built by cloning the one it suspended on, and the clone carries that future's loop - so a handler that suspends on a Hyperman worker resumes on the same loop. And $c->await($f), which blocks and pumps, is a different thing from the await keyword, which suspends; both are legal in one scope.
The AWAIT_* methods are the protocol. Call the documented names above rather than those.
SEE ALSO
Punk, "promise" in Punk::Context, "Future" in Hyperman.
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)