Como posso propagar e capturar erros lançados em outro segmento no Raku?

9

Qual é a melhor maneira de propagar erros a partir de um thread separado (por exemplo, bloco inicial, Proc :: Async ou sub contendo estes). Simplesmente encapsular o código que gera um novo encadeamento em um bloco try / CATCH não funciona, e o uso de aguardar funciona apenas dependendo do valor de retorno da sub-rotina (isto é, um sub-retorno não funcionará com a abordagem de espera).

ryn1x
fonte
Talvez fooe barpossa ser eliminado aqui?
jjmerelo 31/03
11
Ainda estou tendo problemas com esse cenário ... simplesmente não é possível em Raku e requer a reestruturação das classes reais? Isso não seria o ideal, porque eu não quero manipulação de erro específica de aplicativo em classes que podem ser reutilizadas em outros lugares ...
ryn1x 14/04
@ ryn1x Eu sugiro que você considere restaurar esta pergunta à sua forma original. Em seguida, adicione uma observação explicando que, embora algumas de nossas respostas tenham resolvido a declaração do problema fornecida no corpo de sua pergunta, você estava realmente procurando algo mais geral. Além disso, embora a resposta que você aceitou seja mais geral, você concluiu que ainda não foi suficientemente geral. Além disso, você tentou uma recompensa, além de pedir mais generalidade, mas isso não ajudou. Em seguida, escreva uma nova pergunta, vinculando novamente a esta, com um exemplo que você acredita que ilustra o problema.
raiph 21/04
A resposta atual é completamente suficiente para mim. Mudei a pergunta porque estava ficando muito longa e específica para quem acaba aqui.
ryn1x 22/04

Respostas:

6

Use await.

Por exemplo, substitua estas três linhas no seu código:

foo;
bar;
baz;

com:

await foo, bar, baz;
raiph
fonte
Isso funciona, mas não foi dimensionado para o meu problema real, porque foo, bar e baz são realmente métodos que retornam a si mesmos. Eu atualizei a pergunta e o exemplo.
ryn1x 31/03
5

Teoricamente, esse código deve morrer :

A partir da versão 6.d do idioma, o prefixo da instrução start usado no contexto do coletor anexará automaticamente um manipulador de exceções. Se ocorrer uma exceção no código fornecido, ele será impresso e o programa será encerrado, como se fosse lançado sem nenhum prefixo de instrução de início envolvido.

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 

Nesse caso, é uma situação estranha, porque você não está cumprindo a promessa (está retornando), mas eventualmente a afunda porque a executa em um contexto nulo.

A mesma documentação fornece a solução: não afunde o contexto:

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

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

Como seu programa não morre, eu diria que você está na segunda situação. Por alguma razão, não está afundado. Seja qual for a situação, a solução é a mesma: você precisa capturar a exceção dentro do mesmo bloco de código.

Solução: awaita promessa (que não afunda) ou a atribui a alguma variável, para que o código circundante morra também. Mas, respondendo ao seu OP, não, você não pode capturar uma exceção de outro encadeamento, da mesma forma que não pode capturar uma exceção de outro bloco.

jjmerelo
fonte
Obrigado por tudo isso. Na verdade, preciso ser mais específico do que no meu OP. Não estou chamando no contexto do coletor e a solução de aguardar também não está funcionando porque as funções do OP são na verdade métodos que retornam a si mesmos. Eu atualizei a pergunta e o exemplo.
ryn1x 31/03
4

Seguindo a convenção usada em Ir para passar rotinas fora de uso usando canais, encontrei a mesma abordagem para trabalhar em Raku. Pode-se usar um canal para enviar erros fora do código assíncrono a ser tratado pelo thread principal.

Exemplo:

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
fonte