¿Cómo puedo propagar y detectar errores lanzados en otro hilo en Raku?


9

¿Cuál es la mejor manera de propagar errores desde un hilo separado (por ejemplo, bloque de inicio, Proc :: Async o subcontenido que los contiene)? Simplemente envolver el código que hace girar un nuevo hilo en un bloque try / CATCH no funciona, y el uso de esperar solo funciona dependiendo del valor de retorno de la subrutina (es decir, un auto de retorno secundario no funcionará con el enfoque de espera).


Tal vez fooy barpuede ser eliminado aquí?
jjmerelo

1
Todavía tengo problemas con este escenario ... ¿simplemente no es posible en Raku y requiere reestructurar las clases reales? Eso no sería ideal porque no quiero el manejo de errores específicos de la aplicación en clases que se pueden reutilizar en otro lugar ...
ryn1x

@ ryn1x Le sugiero que considere restaurar esta pregunta a su forma original. Luego, agregue una nota al comienzo que explique que, aunque algunas de nuestras respuestas resolvieron el enunciado del problema que figura en el cuerpo de su pregunta, en realidad estaba buscando algo más general. Además, si bien la respuesta que aceptó fue más general, desde entonces concluyó que aún no era lo suficientemente general. Además, que probaste una recompensa, junto con pedir más generalidad, pero eso no ayudó. Luego escriba una nueva pregunta, vinculándola con esta, con un ejemplo que usted cree que ilustra el problema.
raiph

La respuesta actual es completamente suficiente para mí. Cambié la pregunta porque se estaba haciendo demasiado larga y específica para cualquiera que terminara aquí.
ryn1x

Respuestas:


6

Uso await.

Por ejemplo, reemplace estas tres líneas en su código:

foo;
bar;
baz;

con:

await foo, bar, baz;

Esto funciona, pero no se ajustó a mi problema real porque foo, bar y baz son en realidad métodos que se devuelven. Actualicé la pregunta y el ejemplo.
ryn1x

5

Teóricamente, ese código debería morir :

A partir de la versión 6.d del lenguaje, el prefijo de instrucción de inicio utilizado en el contexto de sumidero adjuntará automáticamente un controlador de excepciones. Si se produce una excepción en el código dado, se imprimirá y el programa se cerrará, como si se lanzara sin ningún prefijo de declaración de inicio involucrado.

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 

En este caso, es una situación extraña porque no estás cumpliendo la promesa (la estás devolviendo), pero eventualmente la hundes porque la estás ejecutando en un contexto vacío.

La misma documentación le brinda la solución: no hunda el 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 su programa no muere, diría que está en la segunda situación. Por alguna razón, no está hundido. Pero sea cual sea la situación, la solución es la misma: debe detectar la excepción dentro del mismo bloque de código.

Solución: awaitla promesa (que no lo hundirá) o la asignará a alguna variable, de modo que el código circundante también muera. Pero respondiendo su OP, no, no puede detectar una excepción de otro hilo, de la misma manera que no puede detectar una excepción de otro bloque.


Gracias por todo esto De hecho, necesito ser más específico que en mi OP. No estoy llamando en contexto de sumidero y la solución de espera tampoco funciona porque las funciones del OP son en realidad métodos que se devuelven. Actualicé la pregunta y el ejemplo.
ryn1x

4

Siguiendo la convención utilizada en Go para pasar errores fuera de las rutinas de go usando canales, encontré el mismo enfoque para trabajar en Raku. Se puede usar un canal para enviar errores fuera del código asincrónico que debe manejar el hilo principal.

Ejemplo:

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;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.