Jak mogę propagować i wychwytywać błędy zgłaszane w innym wątku w Raku?

9

Jaki jest najlepszy sposób na propagowanie błędów z oddzielnego wątku (np. Blok startowy, Proc :: Async lub sub zawierające je). Po prostu owijanie kodu, który wypuszcza nowy wątek w bloku try / CATCH, nie działa, a użycie funkcji czekania działa tylko w zależności od zwracanej wartości podprogramu (tzn. Sub powracające self nie będzie działać z podejściem oczekiwania).

ryn1x
źródło
Może fooi barmoże zostać tutaj wyeliminowany?
jjmerelo
1
Nadal mam problemy z tym scenariuszem ... czy w Raku jest to po prostu niemożliwe i wymaga restrukturyzacji rzeczywistych klas? To nie byłby idealny, ponieważ nie chcę konkretną obsługę błędów aplikacji w klasach, które mogą być ponownie wykorzystane gdzie indziej ...
ryn1x
@ ryn1x Proponuję rozważyć przywrócenie tego pytania do pierwotnej postaci. Następnie na początku dodaj notatkę wyjaśniającą, że chociaż niektóre z naszych odpowiedzi rozwiązały problem podany w treści twojego pytania, tak naprawdę szukałeś czegoś bardziej ogólnego. Ponadto, chociaż odpowiedź, którą zaakceptowałeś, była bardziej ogólna, od tego czasu doszedłeś do wniosku, że nadal nie była wystarczająco ogólna. Ponadto, że próbowałeś nagrody, w połączeniu z proszeniem o więcej ogólności, ale to nie pomogło. Następnie napisz nowe pytanie, powracając do tego pytania, z przykładem, który Twoim zdaniem ilustruje problem.
raiph
Obecna odpowiedź jest dla mnie całkowicie wystarczająca. Zmieniłem pytanie, ponieważ stało się zbyt długie i specyficzne dla każdego, kto tu trafi.
ryn1x

Odpowiedzi:

6

Zastosowanie await.

Na przykład zamień te trzy wiersze w kodzie:

foo;
bar;
baz;

z:

await foo, bar, baz;
raiph
źródło
To działa, ale nie skaluje się do mojego rzeczywistego problemu, ponieważ foo, bar i baz są w rzeczywistości metodami zwracającymi self. Zaktualizowałem pytanie i przykład.
ryn1x
5

Teoretycznie ten kod powinien umrzeć :

Począwszy od wersji 6.d języka, prefiks instrukcji start używany w kontekście ujścia automatycznie dołącza procedurę obsługi wyjątków. Jeśli w danym kodzie wystąpi wyjątek, zostanie wydrukowany, a następnie program zakończy działanie, tak jakby został zgłoszony bez prefiksów instrukcji start.

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 

W tym przypadku jest to dziwna sytuacja, ponieważ nie zatapiasz obietnicy (oddajesz ją), ale ostatecznie zatapiasz, ponieważ uruchamiasz ją w pustym kontekście.

Ta sama dokumentacja daje rozwiązanie: nie zatapiaj kontekstu:

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

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

Ponieważ twój program nie umiera, powiedziałbym, że jesteś w drugiej sytuacji. Z jakiegoś powodu nie jest zatopiony. Ale bez względu na sytuację rozwiązanie jest takie samo: musisz złapać wyjątek w tym samym bloku kodu.

Rozwiązanie: awaitobietnica (która jej nie zatopi) lub przypisz ją do jakiejś zmiennej, aby umarł również otaczający kod. Ale odpowiadając na OP, nie, nie możesz złapać wyjątku z innego wątku, tak samo jak nie możesz złapać wyjątku z innego bloku.

jjmerelo
źródło
Dzięki za to wszystko. Właściwie muszę być bardziej szczegółowy niż w mojej OP. Nie dzwonię w kontekście zlewu, a oczekiwane rozwiązanie również nie działa, ponieważ funkcje z OP są w rzeczywistości metodami zwracającymi self. Zaktualizowałem pytanie i przykład.
ryn1x
4

Zgodnie z konwencją używaną w Go do przekazywania błędów poza procedurami Go za pomocą kanałów, znalazłem to samo podejście do pracy w Raku. Można użyć kanału do wysyłania błędów z kodu asynchronicznego, który ma być obsługiwany przez główny wątek.

Przykład:

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;
ryn1x
źródło