⚙️ forever – Process Manager simple pour Node.js
Guide complet IDEO-Lab sur le daemon "forever" pour Node.js (Keep-Alive, Logs, CLI).
Concept : Keep-Alive (Node.js)
Gardien (Watchdog) simple pour scripts Node.js.
forever Node.js Keep-Alivevs. node app.js
Le problème (Crash, Terminal fermé).
Production Crashvs. PM2 / Supervisor
forever (Simple) vs PM2 (Cluster) vs Supervisor (Général).
Installation (npm)
npm install forever -g.
CLI : forever start
Lancer un script en mode "daemon".
forever startCLI : forever list
Lister les processus (PID, Uptime, Logfile).
forever listCLI : forever stop
Arrêter un script (par index, PID, ou nom).
forever stopCLI : forever restart
Redémarrer un script (Hard restart).
forever restartCLI : stopall / restartall
Gérer tous les processus monitorés.
forever stopallGestion des Logs (Défaut)
Capture stdout/stderr (~/.forever/[uid].log).
CLI : forever logs
Streamer (tail -f) les logs d'un script.
Options : Logs (-l, -o, -e)
Personnaliser les chemins de logs.
-l (logfile) -a (append)Mode Watch (-w)
Redémarrer si fichiers modifiés (Dev, style nodemon).
Options (-c, --uid)
-c python (Autre runtime), --uid (Nom).
Configuration (JSON)
Utiliser un fichier JSON (similaire à ecosystem).
JSON IaCAPI Programmatique
forever-monitor. Utiliser forever dans un script Node.
Limitation : Cluster Mode
Ne gère pas le clustering (Node.js) natif (vs PM2).
Limitation ClusterLimitation : Startup (Boot)
Pas de startup auto (vs PM2). (Nécessite crontab).
Qu'est-ce que forever ?
forever est un gestionnaire de processus (Process Manager) en ligne de commande (CLI), simple et léger, conçu pour les scripts Node.js.
C'est un des "ancêtres" des process managers Node.js (avec nodemon). Son objectif principal est de s'assurer qu'un script (ex: un serveur web) reste "vivant" (Keep-Alive) en production.
Fonctionnement (Watchdog)
forever lance votre script (ex: app.js) en tant que processus enfant (child process), et se met en mode "daemon" (arrière-plan).
Il "surveille" (watch) ce processus enfant. Si le processus enfant crashe (se termine avec un code d'erreur non-zéro), forever le redémarre automatiquement.
node app.js (en Production)Lancer une application en production avec node app.js & (ou npm start &) est une très mauvaise pratique.
1. Crash (Panne)
Si votre application (node app.js) rencontre une exception non-gérée (Unhandled Exception), le processus s'arrête (crash).
Résultat : Votre site est DOWN jusqu'à ce qu'un admin se connecte et le relance manuellement.
Solution forever : forever start app.js. Le daemon forever détecte le crash et redémarre le processus instantanément (Auto-Remediation).
2. Fermeture du Terminal (SIGHUP)
Si vous lancez node app.js & (background) via SSH, le processus est toujours lié à votre session terminal.
Résultat : Lorsque vous fermez votre terminal SSH, le système envoie un signal SIGHUP (Hangup) à tous les processus de cette session. Votre node app.js est tué.
Solution forever : forever start app.js lance le script en tant que daemon "détaché", qui n'est pas lié à votre session SSH.
(Note : Des outils comme nohup ou screen/tmux résolvent aussi ce problème spécifique, mais sans le redémarrage automatique).
forever vs. PM2 vs. Supervisorforever est le "pionnier", mais PM2 et Supervisor sont des solutions plus robustes.
| Critère | forever | PM2 (Moderne Node.js) | Supervisor (Généraliste) |
|---|---|---|---|
| Langage | Node.js | Node.js | Python |
| Usage Principal | Scripts Node.js simples | Applications Node.js (Prod) | Général (Python, Gunicorn, Celery) |
| Keep-Alive | Oui (Crash) | Oui (Crash) | Oui (Crash, Exit codes) |
| Cluster (LB) | Non (Gros inconvénient) | Oui (Natif) (-i max) | Non (Gère N copies, mais sans LB) |
| Startup (Boot) | Non (Manuel, via Cron/systemd) | Oui (pm2 startup) | Non (Géré par systemd) |
| Config (IaC) | JSON (Basique) | Ecosystem.js (Puissant) | .conf (INI) (Robuste) |
| Monitoring | CLI (list, logs) | CLI (monit), Web (PM2 Plus) | CLI (supervisorctl), Web UI |
| Reload (Zero-Downtime) | Non (restart uniquement) | Oui (reload) | Non (restart uniquement) |
Verdict : forever est suffisant pour un petit script simple. Pour toute application Node.js de production (serveur web), PM2 est le standard.
forever start [script]La commande start lance le script en mode "daemon" (arrière-plan).
$ forever start app.js warn: --minUptime not set. Defaulting to: 1000ms warn: --spinSleepTime not set. Defaulting to: 1000ms info: Forever processing file: app.js info: Script TOTO added to list. $ forever list info: Forever processes running data: uid command script forever pid id logfile uptime data: [0] TOTO /usr/bin/node app.js 23456 23458 /home/user/.forever/TOTO.log 1s
uid: L'ID (nom) unique du processus (ici,TOTO, généré aléatoirement si--uidn'est pas défini).command: Le runtime (ex:node).script: Le script (app.js).forever pid: Le PID du daemonforever(parent).pid: Le PID du processusapp.js(enfant).logfile: Le chemin vers le fichier de log (stdout/stderr).
forever listforever list (ou forever ls) est l'équivalent de pm2 list ou supervisorctl status.
$ forever list info: Forever processes running data: uid command script forever pid id logfile uptime data: [0] api /usr/bin/node api.js 23456 23458 /home/user/.forever/api.log 2d 5h 10m data: [1] bot /usr/bin/node bot.js 23500 23502 /home/user/.forever/bot.log 1h 20m data: [2] old /usr/bin/node old.js 0 0 /home/user/.forever/old.log STOPPED
Analyse :
[0] api: (ID0, uidapi) Tourne depuis 2 jours.[1] bot: (ID1, uidbot) Tourne depuis 1h 20m.[2] old: (ID2, uidold) EstSTOPPED. (PID = 0).
forever stopforever stop arrête un processus (il reste dans la liste avec le statut STOPPED).
Méthodes d'identification
Vous pouvez stopper un processus de 4 manières :
# 1. Par l'Index (recommandé) $ forever stop 0 (Arrête l'ID [0] de 'forever list') # 2. Par le 'uid' (si défini, voir 5.2) $ forever stop api # 3. Par le nom du script $ forever stop app.js # 4. Par le PID (du 'child' (enfant)) $ forever stop 23458
forever restartforever restart est un "hard restart" (Stop + Start). Il ne fait pas de "Zero-Downtime reload" (comme PM2).
# Redémarre l'ID [0] $ forever restart 0 info: Stopping process: api info: Process api stopped info: Forever processing file: api.js info: Script api added to list. # (Le PID va changer)
stopall & restartallstopall
Arrête tous les processus RUNNING gérés par forever.
$ forever stopall info: Stopping all running processes info: Process api stopped info: Process bot stopped
restartall
Redémarre tous les processus RUNNING.
forever (comme supervisor) capture stdout (console.log) et stderr (console.error, exceptions) des processus enfants.
Emplacement par Défaut
Par défaut, il crée un fichier de log unique (qui combine stdout/stderr) dans ~/.forever/.
$ forever list data: uid ... logfile data: [0] api ... /home/ideo/.forever/api.log
Rotation : forever ne gère pas la rotation des logs (logrotate) nativement. Les fichiers .log peuvent devenir énormes.
forever logs (Streaming)La commande forever logs est l'équivalent de pm2 logs ou tail -f. Elle "stream" (affiche en temps réel) les logs.
# Streamer les logs d'un script (par index) $ forever logs 0 # Streamer (tail) les logs (force -f) $ forever logs 0 -f # Streamer (par nom de script) $ forever logs api.js # Afficher les 100 dernières lignes (pas de stream) $ forever logs 0 -n 100
Vous pouvez (devez) personnaliser les chemins de logs au lieu d'utiliser ~/.forever/.
| Option | Description |
|---|---|
-l [CHEMIN] | (Logfile) Log stdout ET stderr dans ce fichier (combiné). |
-o [CHEMIN] | (Out file) Log stdout (uniquement) dans ce fichier. |
-e [CHEMIN] | (Error file) Log stderr (uniquement) dans ce fichier. |
-a (ou --append) | (Important) "Append" (Ajouter) aux logs. Si omis, forever restart écrase (overwrite) le fichier log. |
Exemple (Production)
# (Lance api.js)
# (Ajoute les logs 'stdout' à api-out.log)
# (Ajoute les logs 'stderr' à api-err.log)
$ forever start -a -o /var/log/myapp/api-out.log \
-e /var/log/myapp/api-err.log \
app.js-w) (Développement)L'option -w (ou --watch) est l'équivalent de nodemon.
forever va "surveiller" (watch) le dossier (watchDirectory) du script. Si un fichier (ex: app.js) est modifié (sauvegardé), forever redémarre (restart) automatiquement le processus.
# 1. Démarrer en mode "watch" $ forever start -w app.js # 2. (Modifier et sauvegarder app.js) # (forever détecte le changement) info: Changes detected in /path/to/app.js. Restarting... info: Process app.js stopped info: Forever processing file: app.js ...
Attention : Ne jamais utiliser --watch en Production (sauf cas très spécifique). C'est un outil de Développement.
-c, --uid)| Option | Description | Exemple |
|---|---|---|
--uid [nom] | Définit un nom (uid) personnalisé pour le processus (au lieu d'un nom aléatoire comme "TOTO"). | forever start app.js --uid "api" |
-c [cmd] | (Command) Spécifie le runtime à utiliser. (Défaut : node). | forever start -c python script.py |
--pidFile [path] | Stocke le PID du daemon forever (parent) dans un fichier. | --pidFile /var/run/forever.pid |
--max [n] | Nombre maximum de redémarrages (défaut : 10). | --max 5 |
--minUptime [ms] | Temps (ms) qu'un script doit tourner pour être "stable". | --minUptime 5000 (5 sec) |
forever (comme PM2) peut être lancé avec un fichier de configuration (JSON) pour définir les options (IaC).
Fichier (config.json)
[
{
// (Process 1)
"uid": "api-web",
"script": "app.js",
"watch": false,
"logFile": "/var/log/myapp/api.log",
"append": true,
"max": 10,
"minUptime": 5000
},
{
// (Process 2)
"uid": "worker",
"script": "worker.js",
"logFile": "/var/log/myapp/worker.log",
"append": true
}
]Lancement (CLI)
# Démarrer TOUS les scripts du JSON $ forever start config.json # Stopper TOUS les scripts du JSON $ forever stop config.json
forever-monitor)forever peut être utilisé comme une bibliothèque (library) Node.js (forever-monitor) pour gérer des processus enfants depuis votre propre code.
const forever = require('forever-monitor');
// 1. Définir l'enfant (child)
const child = new (forever.Monitor)('mon_script_enfant.js', {
max: 3,
silent: false,
args: ['--port=8080']
});
// 2. Événements (Events)
child.on('watch:restart', (info) => {
console.log('Restarting script because ' + info.file + ' changed');
});
child.on('restart', () => {
console.log('Forever restarting script for ' + child.times + ' time');
});
child.on('exit:code', (code) => {
console.log('Script exited with code ' + code);
});
// 3. Démarrer
child.start();
C'est la limitation majeure de forever par rapport à PM2.
forever ne supporte pas le "Clustering" (Load Balancing) natif. Il n'a pas d'équivalent au pm2 start -i max.
Le Problème (Node.js Mono-Thread)
Si vous lancez forever start app.js sur un serveur à 16 Cœurs, votre application ne tournera que sur 1 Cœur, laissant 15 Cœurs (94% du serveur) inutilisés.
Contournement (Manuel)
Le seul moyen de contourner (maladroitement) est de lancer 16 copies manuelles (ou via JSON) sur 16 ports différents (8001, 8002...) et de mettre un Load Balancer (Nginx, HAProxy) en façade.
Conclusion : forever est obsolète pour les serveurs web Node.js. PM2 (2.3) gère cela nativement (via le module cluster de Node.js).
forever ne fournit pas d'utilitaire (comme pm2 startup) pour créer automatiquement un service de démarrage (systemd ou init.d).
Le Problème
Si vous lancez forever start app.js et que le serveur (VM) redémarre, vos applications sont DOWN. Le daemon forever lui-même n'a pas été relancé.
Solution (Manuelle)
Vous devez manuellement créer un service systemd (ou un crontab @reboot) pour lancer forever au démarrage.
Exemple (Crontab @reboot)
# (Exécuter 'crontab -e' pour l'utilisateur 'ideo') # (Au redémarrage, lancer 'forever' pour # démarrer TOUS les scripts sauvegardés) @reboot /usr/bin/forever startall
Exemple (systemd)
Créer un /etc/systemd/system/forever.service (Complexe).
