
# Que PM2 sobreviva a un reinicio del servidor

El servidor reinició y la web no volvió. Volvió una hora después, cuando alguien lanzó un despliegue. Parece un problema de despliegue y no lo es: lo único que hizo ese despliegue fue ejecutar `pm2 start` otra vez a mano.

Para que tu aplicación arranque sola hacen falta dos cosas distintas, y cada una sin la otra no sirve de nada.

## Las dos mitades

**`pm2 save`** escribe la lista de procesos actual en `~/.pm2/dump.pm2`. PM2 relanza lo que haya en ese fichero y nada más. Un script de despliegue que hace `pm2 delete` y `pm2 start` pero no guarda deja el dump desfasado, o vacío si nunca llegó a escribirse.

**`pm2 startup`** instala una unidad de systemd que ejecuta `pm2 resurrect` en el arranque, y esa unidad es la que lee el dump.

Una sin la otra te da un arranque que no levanta nada, o una lista guardada que no lee nadie.

## La trampa

Ejecutar `pm2 startup` con un usuario sin privilegios **no instala absolutamente nada**. Detecta systemd, calcula el comando que instalaría la unidad, lo imprime y termina. La salida es larga, va en verde y acaba con una línea sobre copiar y pegar el comando. Parece que ha funcionado. No ha pasado nada.

Así que ejecútalo como root, y comprueba el resultado con systemd, no con lo que te haya imprimido PM2.

## El orden correcto

La aplicación tiene que estar levantada antes de guardar, o guardarás una lista vacía.

```bash
# como <user> — confirma que la app está corriendo
pm2 status
```

```bash
# como root — instala la unidad para ese usuario
env PATH=$PATH:/usr/bin pm2 startup systemd -u <user> --hp /home/<user>
```

El prefijo `env PATH=$PATH:/usr/bin` no es adorno. El `PATH` de root normalmente no lleva Node, y la unidad se queda con la ruta que tenía cuando se generó. Sin ese prefijo la unidad existe, pero en el arranque no encuentra `node`.

```bash
# otra vez como <user> — escribe el dump
pm2 save
```

## Comprueba cada mitad por separado

Fallan por separado, así que se miran por separado.

```bash
systemctl is-enabled pm2-<user>
```

Tiene que responder `enabled`. Cualquier otra cosa, sea `disabled` o `Failed to get unit file state`, significa que la unidad nunca se instaló, diga lo que diga PM2.

```bash
grep -o '"name":"[^"]*"' /home/<user>/.pm2/dump.pm2
```

Ahí tiene que salir `<app>`. Si el fichero no existe, o el grep no imprime nada, es que `pm2 save` nunca se ejecutó con la aplicación levantada.

## Pruébalo sin reiniciar

No hace falta reiniciar una máquina en producción para saber si esto funciona.

```bash
# como <user>
pm2 kill
```

```bash
# como root
systemctl start pm2-<user>
```

```bash
# como <user>
pm2 status
curl -sf http://127.0.0.1:3000/health
```

Si `<app>` vuelve a aparecer en línea, las dos mitades funcionan. Es exactamente lo que hace el arranque.

**Nunca ejecutes `pm2 save` después de `pm2 kill`.** Con el demonio muerto la lista de procesos está vacía, y al guardar escribes ese vacío en el dump, cargándote justo lo que estabas probando. Si lo haces por inercia, levanta la aplicación otra vez y repite el `pm2 save`.

## Mete `pm2 save` en el script de despliegue

El dump se desfasa en cuanto un despliegue toca el proceso. Si tu script borra y vuelve a arrancar, tiene que guardar después:

```bash
pm2 delete <app> || true
pm2 start ecosystem.config.cjs --only <app>
pm2 save
```

El `|| true` importa en la primera ejecución, cuando no hay nada que borrar y `pm2 delete` sale con código distinto de cero, lo que mata el script entero si tienes `set -e`.

Sin esa última línea todo lo anterior sigue funcionando hasta el primer despliegue que renombre la aplicación, cambie el número de instancias o toque el punto de entrada. A partir de ahí el dump describe un proceso que ya no existe, y el siguiente reinicio resucita eso.

## Una cosa más sobre el orden de arranque

La unidad que se genera lleva `After=network.target`. No está ordenada después de tu base de datos. En un arranque en frío la aplicación puede levantarse antes de que MariaDB o PostgreSQL acepten conexiones, fallar en su primera consulta y salir.

Normalmente esto se arregla solo: PM2 reinicia el proceso, en el segundo o tercer intento la base de datos ya está lista y la web sube. La pista es un contador de reinicios por encima de cero en un proceso que por lo demás está sano, en la columna `↺` de `pm2 status`.

Si no se recupera, entonces sí, ordena la unidad de forma explícita:

```bash
sudo systemctl edit pm2-<user>
```

```ini
[Unit]
After=network.target mariadb.service
```

Añade eso solo si lo has visto fallar. Ordenar una unidad detrás de un servicio lento, o que vive en otra máquina, te cambia un arranque que reintenta por uno que se queda colgado.

[Analiza tu web](/es) · [Más artículos](/es/blog) · [Sobre AgentReady](/es/about)
