asynchronoushacklang

timeout for async calles in Hack


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.


Solution

  • 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 Conditions 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().