Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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).

like image 267
ryn1x Avatar asked Mar 30 '20 23:03

ryn1x


People also ask

How do you catch an exception when joining a thread?

To catch the exception in the caller thread we maintain a separate variable exc, which is set to the exception raised when the called thread raises an exception. This exc is finally checked in the join () method and if is not None, then join simply raises the same exception.

How to invoke a thread from a class?

For invoking a thread, the caller thread creates a thread object and calls the start method on it. Once the join method is called, that initiates its execution and executes the run method of the class object.

Which thread is the caught exception raised in Python?

Thus, the caught exception is raised in the caller thread, as join returns in the caller thread (Here The Main Thread) and is thus handled correspondingly. Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.

What happens when you spawn a future on a new thread?

If you spawn a future on a new thread using std::async(std::launch::async, ...); and that future’s worker throws an exception, when you later call get() on the future it will emit that exception.


3 Answers

Use await.

For example, replace these three lines in your code:

foo;
bar;
baz;

with:

await foo, bar, baz;
like image 158
raiph Avatar answered Oct 25 '22 08:10

raiph


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;
like image 41
ryn1x Avatar answered Oct 25 '22 10:10

ryn1x


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.

like image 40
jjmerelo Avatar answered Oct 25 '22 09:10

jjmerelo