Matar de verdad
Pedirle a un proceso que termine no es lo mismo que matarlo, y matarlo a él no mata a sus hijos. Los dos pasos, los nietos huérfanos y el cierre de la aplicación.
Los dos pasos
pub async fn terminar(child: &mut Child) { let _ = child.pedir_terminacion(); // paso 1 match timeout(Duration::from_secs(3), child.wait()).await { Ok(_) => {} // terminó solo Err(_) => { let _ = child.kill().await; } // paso 2 }}Tres segundos suele bastar. Menos no le da tiempo a cerrar ficheros grandes; mucho más hace que cerrar tu aplicación se sienta lento.
Los nietos
La sutileza que produce los huérfanos más difíciles de encontrar: matar a un proceso no mata a los que él haya lanzado.
Si tu aplicación lanza un guion, y ese guion lanza la herramienta de verdad, matar el guion deja la herramienta viva, ahora sin padre y sin nadie que la vigile.
La primera es la que más rinde, y merece revisarse: buena parte de los guiones intermedios que la gente lanza existen para encadenar dos órdenes, y eso se hace mejor desde Rust.
El cierre de la aplicación
Lo del nivel 25, aplicado aquí:
- En el cierre normal, recorrer la lista de procesos vivos del nivel 47.1 y terminarlos con los dos pasos. Y esperar a que terminen antes de salir, con un límite razonable.
- En el cierre inesperado —tu aplicación muere de golpe— no hay ocasión de hacer nada. Y por eso hace falta lo siguiente.
Huérfanos de sesiones anteriores
La red de seguridad que casi nadie pone:
// al arrancar: ¿quedó algo de la última vez?for pid in leer_pids_registrados()? { if proceso_vive(pid) && es_nuestro(pid) { log::warn!("huérfano de una sesión anterior: {pid}"); matar(pid); }}Y las dos comprobaciones importan. Que el proceso viva no basta: los identificadores se reutilizan, y matar por identificador sin comprobar que es tuyo puede terminar un proceso ajeno del usuario. La comprobación de que es el tuyo —por el nombre del ejecutable, o por algo que dejaste en su entorno— es lo que hace segura esta limpieza.
Y el fichero donde se registran va en el directorio de datos, escrito al lanzar y borrado al terminar bien.