Saltar al contenido

Cuando el acompañante es un servidor

Un proceso de larga vida que tu aplicación arranca y con el que habla: puertos, arranque, salud, y las cuatro cosas que salen mal cuando el hijo vive tanto como la ventana.

Cuándo tiene sentido

La regla: si arrancar cuesta menos de un segundo y no hay estado que conservar, proceso corto. El de larga vida es para lo que carga algo pesado o mantiene algo caliente.

El canal

Dos opciones, y una es claramente mejor en escritorio:

  • Un puerto de red local. Simple, funciona en todas partes, y tiene dos problemas: el puerto puede estar ocupado y cualquier otro programa de la máquina puede hablar con tu servidor. Lo segundo es lo importante y se olvida siempre.
  • Un canal local del sistema —un socket de dominio o una tubería con nombre—. No usa puertos, no es accesible desde la red, y sus permisos son los del sistema de ficheros. Es lo correcto cuando la herramienta lo soporta.

Si tiene que ser un puerto:

El paso 3 merece énfasis: un servidor local sin autenticación es alcanzable desde el navegador del usuario. Es una vía real y conocida, y el testigo por sesión la cierra con diez líneas.

Saber cuándo está listo, y cuándo murió

Las dos operaciones que hay que implementar sí o sí:

Rust
// listo: sondear hasta que responda, con límiteasync fn esperar_listo(url: &str, limite: Duration) -> Result<(), Error> {    let hasta = Instant::now() + limite;    loop {        if salud(url).await.is_ok() { return Ok(()); }        if Instant::now() > hasta { return Err(Error::NoArranco); }        sleep(Duration::from_millis(100)).await;    }}
  • No supongas que está listo porque el proceso arrancó. Arrancar y estar sirviendo son cosas distintas, y entre las dos puede haber segundos.
  • Y vigila que siga vivo. Un proceso hijo puede morir por su cuenta —sin memoria, un fallo interno— y tu aplicación seguiría enviándole peticiones que nadie contesta. Detectarlo y reiniciarlo una vez, avisando si vuelve a morir.
  • Con un límite de reintentos: reiniciar en bucle un proceso que muere al arrancar consume la máquina del usuario sin arreglar nada.

No dejarlo huérfano

La responsabilidad más importante, y la que más se incumple:

  • Matarlo en el cierre de tu aplicación. Nivel 25, y también en el cierre inesperado si el sistema lo permite.
  • Y comprobar al arrancar si quedó uno de una sesión anterior. Si tu aplicación murió de golpe, puede haber un proceso huérfano; encontrarlo y matarlo antes de lanzar otro evita acumularlos.

El síntoma de no hacerlo: un usuario con cinco copias del mismo servidor consumiendo memoria, que descubre por el ventilador y atribuye —con razón— a tu aplicación.