I am looking how to achieve what https://docs.python.org/3/library/asyncio-task.html#timeouts gives me, but in hack. I just want to timeout my async call in 30 minutes.
In the HSL there is an undocumented but long-standing Condition
class that allows async blocks to signal each other.
(Condition
itself wraps the internal ConditionWaitHandle
async primitive which has been around since the dawn of Hack async.)
You can implement a timeout by having the work and a timeout block race to signal a Condition
:
<?hh // strict
use namespace HH\Asio;
class TimeoutException extends \Exception {}
function timeout<T>(Awaitable<T> $work, int $timeout): Awaitable<T> {
$condition = new HH\Lib\Async\Condition();
$work_ = async {
try {
$res = await $work;
$condition->succeed($res);
}
catch(Exception $e) {
$condition->fail($e);
}
};
$timeout_ = async { await Asio\usleep($timeout); $condition->fail(new TimeoutException()); };
return $condition->waitForNotificationAsync(async { concurrent { await $work_; await $timeout_; } });
}
<<__EntryPoint>>
async function main(): Awaitable<void> {
$work = Asio\usleep((int)1E12);
try {
await timeout($work, (int)1E6);
}
catch(TimeoutException $e) { echo "Timed out"; }
}
If you use Condition
s more widely just be aware that they can't be signalled twice and will raise HH\InvariantException
to the loser of any races to signal them. Here those exceptions are confined to the async block wrappers in timeout()
.