How can I timeout a promise in Raku?

jja :

I know I can schedule a Promise to be kept in a given amount of time with

my $promise = Promise.in($seconds);

but how can I schedule it to be broken? Specifically, I'm thinking of a promise that will "timeout", so that it has up to a certain amount of time to be kept or else it will fail.

I can do this with another Promise, like so:

my $promise = Promise.new;
...
Promise.in($seconds).then: { $promise.break };

But this feels a bit ... wasteful. Is there a better way to do this?

Jonathan Worthington :

A common pattern is to write something like this:

await Promise.anyof($the-promise, Promise.in(10));
if $the-promise {
    # it finished ahead of the timeout
}
else {
    # it timed out
}

That doesn't manifest itself as a broken Promise, though that's not all bad (since you need to distinguish cancellation vs. error in many cases anyway, so you'd still have to do some matching on exception type). This factoring also has the advantage that $the-promise does not have to be one that you have access to keep/break.

One could also wrap this up in something like this:

class TimedOut is Exception {}
sub timeout($promise, $time) {
    start {
        await Promise.anyof($promise, Promise.in($time));
        $promise ?? await($promise) !! die(TimedOut.new)
    }
}

Which will again work with any $promise, pass on the result or exception, and throw a timed-out exception otherwise.

The thing to keep in mind with all of these is that they don't actually effect any cancellation of work in progress. That may not matter, or it might be important. If the latter, you'll probably want either:

  • A Promise that you use to convey cancellation having taken place; you keep it when cancelling, and poll it in the code that will do the cancellation
  • To look at using the Supply paradigm instead, where there is a cancellation model (closing the tap).

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=29550&siteId=1