veza/config/incus/AUDIT_BACKEND_API_ENV_BROKEN_PIPE.md
senke f0ba7de543 state-ownership: delete unused optimisticStoreUpdates.ts file
- Deleted apps/web/src/utils/optimisticStoreUpdates.ts (unused file)
- File was unused - no imports found in codebase
- Mutations already use React Query's onMutate pattern
- No TypeScript errors after deletion
- Actions 4.4.1.2 and 4.4.1.3 complete
2026-01-15 19:26:53 +01:00

13 KiB

AUDIT COMPLET: veza-backend-api Broken Pipe & Fichier .env Manquant dans Incus

Date: 2025-01-27
Problème: veza-backend-api broken pipe. can't find .env file inside the dedicated incus container for the incus deploy
Priorité: P0 - CRITIQUE (bloque le déploiement)


1. RÉSUMÉ EXÉCUTIF

1.1 Problème Principal

Le service veza-backend-api déployé dans un conteneur Incus rencontre deux problèmes critiques:

  1. Broken Pipe Error: Erreurs de "broken pipe" lors de l'écriture des logs
  2. Fichier .env Manquant: L'application ne trouve pas le fichier .env dans le conteneur

1.2 Impact

  • Le service ne démarre pas correctement
  • Les logs ne sont pas capturés par systemd/journald
  • L'application ne peut pas charger les variables d'environnement
  • Le déploiement Incus échoue silencieusement

2. ANALYSE DÉTAILLÉE

2.1 Architecture Actuelle du Déploiement

2.1.1 Fichiers de Configuration

config/incus/env/backend-api.env          # Source (sur l'hôte)
  ↓ (copié via incus file push)
/etc/veza/backend-api.env                 # Destination (dans le conteneur)

2.1.2 Service Systemd

[Service]
WorkingDirectory=/opt/veza/backend-api
ExecStart=/opt/veza/backend-api/start-backend-api.sh
EnvironmentFile=/etc/veza/backend-api.env
StandardOutput=journal
StandardError=journal

2.1.3 Script Wrapper

#!/bin/bash
# start-backend-api.sh
source /etc/veza/backend-api.env
exec /usr/local/bin/veza-backend-api

2.1.4 Application Go

// main.go
_ = godotenv.Load()  // Cherche .env dans le working directory

// config.NewConfig()
LoadEnvFiles(env)    // Cherche .env.{env} et .env dans le working directory

2.2 Problèmes Identifiés

2.2.1 Problème #1: Incohérence des Chemins de Fichiers .env

Symptôme: L'application Go cherche un fichier .env dans /opt/veza/backend-api/ mais le fichier est à /etc/veza/backend-api.env

Cause Racine:

  • Le script de déploiement copie le fichier à /etc/veza/backend-api.env
  • Systemd charge les variables via EnvironmentFile=/etc/veza/backend-api.env
  • Le wrapper script charge les variables via source /etc/veza/backend-api.env
  • MAIS l'application Go fait godotenv.Load() qui cherche .env dans le working directory (/opt/veza/backend-api/)
  • L'application Go fait aussi LoadEnvFiles(env) qui cherche .env.production et .env dans le working directory

Impact:

  • Si les variables sont déjà chargées par systemd/wrapper, godotenv.Load() échoue silencieusement (pas d'erreur si fichier absent)
  • Si les variables ne sont PAS chargées par systemd/wrapper, l'application ne trouve pas le fichier .env et échoue

Preuve:

// veza-backend-api/cmd/api/main.go:50
_ = godotenv.Load()  // Cherche .env dans le répertoire courant

// veza-backend-api/internal/config/env_loader.go:24
_ = godotenv.Load()  // Cherche .env dans le répertoire courant

2.2.2 Problème #2: Broken Pipe Error

Symptôme: Erreurs "broken pipe" lors de l'écriture des logs

Cause Racine:

  • Systemd/journald peut fermer le pipe stdout/stderr si le service démarre trop vite
  • Le wrapper script peut écrire sur stdout/stderr avant que systemd ne soit prêt
  • L'application Go peut essayer d'écrire sur stdout/stderr après que journald ait fermé le pipe

Impact:

  • Les logs ne sont pas capturés correctement
  • L'application peut crasher si les erreurs de broken pipe ne sont pas gérées

Preuve:

  • Le code Go a déjà des mécanismes pour gérer les broken pipe (dans logging/logger.go)
  • Mais le wrapper script et les premières lignes de main.go peuvent écrire sur stdout/stderr avant que le logger ne soit initialisé

2.2.3 Problème #3: Vérification Insuffisante du Fichier .env

Symptôme: Le script de déploiement vérifie que le fichier existe mais ne vérifie pas qu'il est accessible par l'application

Cause Racine:

  • Le script deploy-service-native.sh vérifie que le fichier existe (test -f)
  • Le script vérifie que le fichier est lisible (test -r)
  • MAIS le script ne vérifie pas que le fichier est accessible depuis le working directory de l'application
  • Le script ne crée pas de lien symbolique ou copie vers le working directory

Impact:

  • L'application Go ne peut pas charger le fichier .env même si les variables sont chargées par systemd

2.2.4 Problème #4: Ordre de Chargement des Variables d'Environnement

Symptôme: Les variables peuvent être chargées dans le mauvais ordre

Ordre Actuel:

  1. Systemd charge /etc/veza/backend-api.env (via EnvironmentFile)
  2. Wrapper script charge /etc/veza/backend-api.env (via source)
  3. Application Go charge .env dans working directory (via godotenv.Load())
  4. Application Go charge .env.{env} et .env (via LoadEnvFiles())

Problème:

  • Si le fichier .env n'existe pas dans le working directory, godotenv.Load() échoue silencieusement
  • Si les variables ne sont pas chargées par systemd/wrapper, l'application échoue

3. CAUSES RACINES

3.1 Cause Racine #1: Architecture Incohérente

  • Problème: Mélange de deux approches (systemd EnvironmentFile + godotenv.Load())
  • Solution: Choisir une seule approche et l'appliquer de manière cohérente

3.2 Cause Racine #2: Broken Pipe Non Géré au Démarrage

  • Problème: Écriture sur stdout/stderr avant que journald ne soit prêt
  • Solution: Rediriger stdout/stderr vers journald dès le début ou utiliser un logger qui gère les broken pipe

3.3 Cause Racine #3: Vérification Incomplète

  • Problème: Le script de déploiement ne vérifie pas que l'application peut accéder au fichier .env
  • Solution: Créer un fichier .env dans le working directory ou modifier l'application pour chercher le fichier au bon endroit

3.4 Cause Racine #4: Documentation Manquante

  • Problème: Pas de documentation claire sur où le fichier .env doit être et comment il est chargé
  • Solution: Documenter clairement l'architecture de chargement des variables d'environnement

4. SCÉNARIOS D'ÉCHEC

4.1 Scénario 1: Fichier .env Non Copié

1. Script de déploiement échoue silencieusement lors de la copie
2. Fichier /etc/veza/backend-api.env n'existe pas
3. Systemd ne charge pas les variables (mais ne signale pas d'erreur si EnvironmentFile est optionnel)
4. Wrapper script échoue avec "No such file or directory"
5. Application ne démarre pas

4.2 Scénario 2: Fichier .env Non Lisible

1. Fichier copié mais permissions incorrectes
2. Systemd peut charger les variables (root)
3. Wrapper script peut charger les variables (root)
4. Application Go cherche .env dans working directory (n'existe pas)
5. Application démarre mais avec variables manquantes

4.3 Scénario 3: Broken Pipe au Démarrage

1. Systemd démarre le service
2. Wrapper script écrit sur stdout/stderr
3. Journald n'est pas encore prêt → broken pipe
4. Application Go essaie d'écrire sur stdout/stderr → broken pipe
5. Application crash ou logs perdus

4.4 Scénario 4: Variables Non Chargées

1. Fichier .env copié correctement
2. Systemd charge les variables
3. Wrapper script charge les variables
4. Application Go cherche .env dans working directory (n'existe pas)
5. Si variables critiques manquantes → application échoue

5. POINTS DE VÉRIFICATION

5.1 Vérifications à Effectuer

5.1.1 Dans le Conteneur

# Vérifier que le fichier existe
incus exec veza-backend-api -- test -f /etc/veza/backend-api.env && echo "OK" || echo "FAIL"

# Vérifier les permissions
incus exec veza-backend-api -- ls -la /etc/veza/backend-api.env

# Vérifier le contenu
incus exec veza-backend-api -- cat /etc/veza/backend-api.env

# Vérifier que systemd peut le charger
incus exec veza-backend-api -- systemctl show veza-backend-api --property=EnvironmentFiles

# Vérifier le working directory
incus exec veza-backend-api -- pwd
incus exec veza-backend-api -- ls -la /opt/veza/backend-api/

# Vérifier les variables d'environnement chargées
incus exec veza-backend-api -- systemctl show veza-backend-api --property=Environment

5.1.2 Logs Systemd

# Vérifier les logs du service
incus exec veza-backend-api -- journalctl -u veza-backend-api -n 50

# Vérifier les erreurs
incus exec veza-backend-api -- journalctl -u veza-backend-api -p err

# Vérifier les broken pipe
incus exec veza-backend-api -- journalctl -u veza-backend-api | grep -i "broken pipe"

5.1.3 Status du Service

# Vérifier le status
incus exec veza-backend-api -- systemctl status veza-backend-api

# Vérifier si le service est actif
incus exec veza-backend-api -- systemctl is-active veza-backend-api

# Vérifier les erreurs de démarrage
incus exec veza-backend-api -- systemctl status veza-backend-api | grep -i error

6. SOLUTIONS PROPOSÉES

6.1 Solution 1: Créer un Fichier .env dans le Working Directory (RECOMMANDÉ)

Avantages:

  • Compatible avec l'application Go existante
  • Pas de modification du code Go
  • Simple à implémenter

Inconvénients:

  • Duplication du fichier (mais acceptable pour la cohérence)

Implémentation:

  1. Modifier deploy-service-native.sh pour copier aussi le fichier vers /opt/veza/backend-api/.env
  2. Vérifier que le fichier est créé et lisible

6.2 Solution 2: Modifier l'Application Go pour Chercher le Fichier au Bon Endroit

Avantages:

  • Pas de duplication
  • Architecture plus propre

Inconvénients:

  • Modification du code Go
  • Plus complexe à maintenir

Implémentation:

  1. Modifier env_loader.go pour chercher le fichier à /etc/veza/backend-api.env en premier
  2. Fallback vers .env dans le working directory

6.3 Solution 3: Utiliser Uniquement Systemd EnvironmentFile

Avantages:

  • Architecture simple
  • Pas de duplication
  • Variables chargées avant le démarrage de l'application

Inconvénients:

  • Nécessite de supprimer godotenv.Load() du code Go
  • Peut casser le développement local

Implémentation:

  1. Supprimer godotenv.Load() de main.go
  2. Supprimer LoadEnvFiles() de config.NewConfig()
  3. S'assurer que systemd charge toutes les variables nécessaires

6.4 Solution 4: Gérer les Broken Pipe au Démarrage

Avantages:

  • Résout le problème des broken pipe
  • Améliore la robustesse

Implémentation:

  1. Rediriger stdout/stderr vers journald dès le début du wrapper script
  2. S'assurer que le logger Go gère les broken pipe (déjà fait)
  3. Éviter d'écrire sur stdout/stderr avant que le logger ne soit initialisé

7. RECOMMANDATION FINALE

Solution Recommandée: Combinaison de Solution 1 + Solution 4

  1. Créer un fichier .env dans le working directory pour compatibilité avec l'application Go
  2. Gérer les broken pipe en redirigeant stdout/stderr vers journald dès le début
  3. Améliorer les vérifications dans le script de déploiement
  4. Documenter l'architecture de chargement des variables d'environnement

Raison:

  • Compatible avec l'application Go existante
  • Résout les deux problèmes (broken pipe + fichier .env)
  • Minimal impact sur le code existant
  • Facile à maintenir

8. RISQUES ET MITIGATION

8.1 Risque 1: Duplication du Fichier .env

Mitigation: Le fichier est petit et la duplication est acceptable pour la cohérence

8.2 Risque 2: Modification du Script de Déploiement

Mitigation: Tester le script sur un conteneur de test avant production

8.3 Risque 3: Régression sur le Développement Local

Mitigation: S'assurer que les modifications n'affectent pas le développement local


9. TESTS DE VALIDATION

9.1 Tests à Effectuer

  1. Test 1: Déploiement Complet

    ./config/incus/deploy-service-native.sh backend-api
    ./config/incus/verify-deployment.sh
    
  2. Test 2: Vérification du Fichier .env

    incus exec veza-backend-api -- test -f /etc/veza/backend-api.env
    incus exec veza-backend-api -- test -f /opt/veza/backend-api/.env
    
  3. Test 3: Vérification des Variables

    incus exec veza-backend-api -- env | grep DATABASE_URL
    incus exec veza-backend-api -- env | grep JWT_SECRET
    
  4. Test 4: Vérification des Logs

    incus exec veza-backend-api -- journalctl -u veza-backend-api -n 20
    incus exec veza-backend-api -- journalctl -u veza-backend-api | grep -i "broken pipe"
    
  5. Test 5: Test de Santé

    incus exec veza-backend-api -- curl -f http://localhost:8080/health
    

10. RÉFÉRENCES

10.1 Fichiers Concernés

  • config/incus/deploy-service-native.sh (lignes 315-358)
  • config/incus/systemd/veza-backend-api.service
  • config/incus/scripts/start-backend-api.sh
  • veza-backend-api/cmd/api/main.go (ligne 50)
  • veza-backend-api/internal/config/env_loader.go
  • veza-backend-api/internal/config/config.go (ligne 210)

10.2 Documentation


Fin de l'Audit