ryn1x
ryn1x

Reputation: 1132

How can I propagate and catch errors thrown in another thread in Raku?

What is the best way to propagate errors out from a separate thread (eg. start block, Proc::Async, or sub containing these). Simply wrapping the code that spins off a new thread in a try/CATCH block does not work, and using await only works depending on the return value of the sub routine (ie. a sub returning self will not work with the await approach).

Upvotes: 9

Views: 232

Answers (3)

ryn1x
ryn1x

Reputation: 1132

Following the convention used in Go to pass errors out of go routines using channels, I found the same approach to work in Raku. One can use a Channel to send errors out of the asynchronous code to be handled by the main thread.

Example:

my $errors = Channel.new;

my $err-supply = $errors.Supply;
$err-supply.tap(-> $e {say "handle error: $e"});

start {
    die "something went horribly wrong";

    CATCH {
        default {
            $errors.send($_);
        }
    }
}

sleep 1;

Upvotes: 4

jjmerelo
jjmerelo

Reputation: 23517

Theoretically, that code should die:

As of the 6.d version of the language, start statement prefix used in sink context will automatically attach an exceptions handler. If an exception occurs in the given code, it will be printed and the program will then exit, like if it were thrown without any start statement prefixes involved.

use v6.c;
start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello␤» 

use v6.d;
start { die }; sleep ⅓; say "hello";
# OUTPUT: 
# Unhandled exception in code scheduled on thread 4 
# Died 
#     in block  at -e line 1 

In this case it's a weird situation because you're not sinking the promise (you're returning it), but eventually you sink it because you're running it in void context.

The same documentation gives you the solution: don't sink the context:

# Don't sink it: 
my $ = start { die }; sleep ⅓; say "hello"; # OUTPUT: «hello␤» 

# Catch yourself: 
start { die; CATCH { default { say "caught" } } };
sleep ⅓;
say "hello";

Since your program does not die, I would say you're in the second situation. For some reason, it's not sunk. But whatever is the situation, the solution is the same: you need to catch the exception inside the same code block.

Solution: await the promise (which will not sink it) or assign it to some variable, so that the surrounding code dies too. But responding your OP, no, you can't catch an exception from another thread, same way you can't catch an exception from another block.

Upvotes: 5

raiph
raiph

Reputation: 32404

Use await.

For example, replace these three lines in your code:

foo;
bar;
baz;

with:

await foo, bar, baz;

Upvotes: 6

Related Questions