Aller au contenu principal

Processus de Migration Amélioré - Aaperture

Ce document décrit le processus amélioré de gestion des migrations de base de données avec validation, backup automatique, logging et rollback.

📋 Vue d'ensemble

Le système de migration amélioré fournit :

  • Validation automatique des migrations avant exécution
  • Backup automatique avant migration en production
  • Logging complet de toutes les migrations (statut, durée, erreurs)
  • Rollback automatique en cas d'échec
  • Monitoring des migrations (durée, taux de succès)
  • Vérification de l'ordre des migrations

🏗️ Architecture

Table migration_logs

Toutes les migrations sont enregistrées dans la table migration_logs :

CREATE TABLE migration_logs (
id UUID PRIMARY KEY,
changeset_id TEXT NOT NULL, -- ID du changeset Liquibase
author TEXT NOT NULL, -- Auteur de la migration
filename TEXT NOT NULL, -- Nom du fichier de migration
status TEXT NOT NULL, -- 'in_progress', 'completed', 'failed', 'rolled_back'
error_message TEXT, -- Message d'erreur si échec
duration_ms INTEGER, -- Durée en millisecondes
backup_file TEXT, -- Fichier de backup créé avant migration
executed_at TIMESTAMPTZ, -- Date d'exécution
rolled_back_at TIMESTAMPTZ, -- Date de rollback (si applicable)
executed_by TEXT, -- Qui/quoi a exécuté la migration
metadata JSONB, -- Métadonnées supplémentaires
created_at TIMESTAMPTZ
);

Scripts de migration

migrate-improved.sh (recommandé)

Script amélioré avec toutes les fonctionnalités :

ENVIRONMENT=production ./infra/migrate-improved.sh

Fonctionnalités :

  • ✅ Validation automatique
  • ✅ Backup avant migration (production uniquement)
  • ✅ Logging dans migration_logs
  • ✅ Rollback automatique en cas d'échec
  • ✅ Monitoring et reporting

Note : Le script migrate.sh basique existe toujours mais est déprécié. Utilisez migrate-improved.sh pour toutes les migrations.

📝 Processus de migration

1. Création d'une migration

# Créer un nouveau dossier de migration
mkdir -p infra/liquibase/changes/0113_ma_nouvelle_migration

# Créer up.sql
cat > infra/liquibase/changes/0113_ma_nouvelle_migration/up.sql << EOF
-- Description de la migration
CREATE TABLE IF NOT EXISTS ma_table (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
EOF

# Créer down.sql
cat > infra/liquibase/changes/0113_ma_nouvelle_migration/down.sql << EOF
-- Rollback de la migration
DROP TABLE IF EXISTS ma_table;
EOF

2. Ajout au changelog

Ajouter l'entrée dans infra/liquibase/changelog-master.yaml :

- changeSet:
id: 0113-ma-nouvelle-migration
author: aaperture
changes:
- sqlFile:
path: changes/0113_ma_nouvelle_migration/up.sql
relativeToChangelogFile: true
splitStatements: false
rollback:
- sqlFile:
path: changes/0113_ma_nouvelle_migration/down.sql
relativeToChangelogFile: true
splitStatements: false

3. Validation locale

# Valider la syntaxe SQL
cd infra
docker compose run --rm liquibase validate

# Ou utiliser le script amélioré
ENVIRONMENT=development ./migrate-improved.sh

4. Test sur staging

# Sur environnement de staging
ENVIRONMENT=staging ./infra/migrate-improved.sh

5. Migration en production

Le script amélioré s'exécute automatiquement dans le pipeline CI/CD :

# Dans .gitlab-ci.yml
ENVIRONMENT=production ./infra/migrate-improved.sh

Processus automatique :

  1. ✅ Validation des migrations
  2. ✅ Vérification de l'ordre
  3. ✅ Backup automatique de la DB
  4. ✅ Exécution des migrations
  5. ✅ Logging dans migration_logs
  6. ✅ Rollback automatique en cas d'échec

🔍 Monitoring

Requêtes SQL utiles

Dernière migration

SELECT * FROM migration_logs
ORDER BY executed_at DESC
LIMIT 1;

Migrations échouées

SELECT * FROM migration_logs
WHERE status = 'failed'
ORDER BY executed_at DESC;

Statistiques des migrations

SELECT
status,
COUNT(*) as count,
AVG(duration_ms) as avg_duration_ms,
MAX(executed_at) as last_execution
FROM migration_logs
GROUP BY status;

Migrations récentes

SELECT
changeset_id,
author,
status,
duration_ms,
executed_at,
error_message
FROM migration_logs
WHERE executed_at > NOW() - INTERVAL '7 days'
ORDER BY executed_at DESC;

🔄 Synchronisation depuis Liquibase

Vue d'ensemble

Si des migrations ont été exécutées directement avec Liquibase (sans passer par le système de logging amélioré), il est possible de synchroniser les logs depuis la table databasechangelog de Liquibase vers migration_logs.

Utilisation

Via l'interface admin

  1. Accéder à l'onglet "Migrations" dans le panneau d'administration
  2. Cliquer sur le bouton "Synchroniser depuis Liquibase"
  3. Le système importe automatiquement les migrations manquantes

Via l'API

# Endpoint admin (nécessite ADMIN_ACCESS)
POST /migrations/sync-from-liquibase

Réponse :

{
"message": "Synced 5 migration(s) from Liquibase",
"synced": 5
}

Fonctionnement

  1. Vérification : Le service vérifie si la table databasechangelog existe
  2. Lecture : Lit tous les changesets exécutés (exectype = 'EXECUTED')
  3. Filtrage : Ignore les changesets déjà présents dans migration_logs
  4. Import : Crée les entrées correspondantes dans migration_logs avec :
    • changeset_id : ID du changeset Liquibase
    • author : Auteur du changeset
    • filename : Nom du fichier de migration
    • status : 'completed' (puisque déjà exécuté)
    • executed_at : Date d'exécution depuis dateexecuted
    • executed_by : 'liquibase-sync'

Cas d'usage

  • Migration manuelle : Si une migration a été exécutée manuellement avec Liquibase
  • Récupération après incident : Si les logs ont été perdus mais que les migrations sont toujours dans databasechangelog
  • Synchronisation initiale : Lors de la mise en place du système de logging amélioré sur une base existante

Limitations

  • Les migrations synchronisées n'ont pas de duration_ms (non disponible dans databasechangelog)
  • Les migrations synchronisées n'ont pas de backup_file (backup non effectué)
  • Seules les migrations avec exectype = 'EXECUTED' sont synchronisées

Prévention des doublons

Le système vérifie automatiquement les changeset_id existants avant d'importer pour éviter les doublons.

🚨 Gestion des erreurs

Rollback automatique

Si une migration échoue, le script tente automatiquement un rollback :

  1. Détection de l'échec
  2. Tentative de rollback automatique
  3. Mise à jour du statut dans migration_logs
  4. Notification (si configuré)

Rollback manuel

Si le rollback automatique échoue :

# Rollback d'une migration
cd infra
docker compose run --rm liquibase rollbackCount 1

# Rollback jusqu'à un tag spécifique
docker compose run --rm liquibase rollback tag_name

Restauration depuis backup

Si une migration cause des problèmes :

  1. Identifier le backup créé avant la migration :

    SELECT backup_file FROM migration_logs
    WHERE executed_at = '2024-01-01 10:00:00';
  2. Restaurer le backup :

    gunzip -c /path/to/backup/postgres-2024-01-01T10-00-00.sql.gz | \
    psql -h localhost -U postgres -d aaperture
  3. Marquer la migration comme rollback :

    UPDATE migration_logs
    SET status = 'rolled_back', rolled_back_at = NOW()
    WHERE id = 'migration-id';

📊 Bonnes pratiques

1. Toujours créer un down.sql

Chaque migration doit avoir un fichier de rollback :

-- up.sql
CREATE TABLE ma_table (...);

-- down.sql
DROP TABLE IF EXISTS ma_table;

2. Tester localement avant de commiter

# Créer une DB de test
createdb aaperture_test

# Tester la migration
ENVIRONMENT=development ./infra/migrate-improved.sh

3. Vérifier les dépendances

Assurez-vous que les migrations sont dans le bon ordre dans changelog-master.yaml.

4. Documenter les migrations complexes

Ajoutez des commentaires dans les fichiers SQL :

-- Migration: 0113-ma-nouvelle-migration
-- Description: Crée la table ma_table pour stocker...
-- Dependencies: Nécessite la migration 0112-create-migration-logs
-- Breaking changes: Aucun

5. Ne jamais modifier une migration déjà appliquée

Si une migration a été appliquée en production, créez une nouvelle migration pour corriger.

🔧 Configuration

Variables d'environnement

# Environnement (development, staging, production)
ENVIRONMENT=production

# Credentials DB (chargés depuis .env)
POSTGRES_DB=aaperture
POSTGRES_USER=postgres
POSTGRES_PASSWORD=secret

# Image Liquibase (définie dans CI/CD)
CI_REGISTRY_IMAGE=registry.gitlab.com/namespace/project
CI_COMMIT_SHORT_SHA=abc123

# Timeout pour migrations (seconds, défaut: 600 = 10 minutes)
MIGRATION_TIMEOUT=600

Note: Le script migrate-improved.sh applique automatiquement un timeout configurable via MIGRATION_TIMEOUT. Voir TIMEOUT_MANAGEMENT.md pour plus d'informations.

Intégration CI/CD

Le script amélioré est appelé automatiquement dans .gitlab-ci.yml :

# 4) Migrations
- |
ssh "$SERVER_USER@$SERVER_HOST" "\
set -eo pipefail; \
export APP_DIR='$APP_DIR'; \
export ENVIRONMENT='production'; \
export CI_REGISTRY='$CI_REGISTRY' CI_REGISTRY_IMAGE='$CI_REGISTRY_IMAGE' CI_COMMIT_SHORT_SHA='$CI_COMMIT_SHORT_SHA'; \
bash '$APP_DIR/infra/migrate-improved.sh'"

📈 Améliorations futures

  • Interface admin pour visualiser les migrations - ✅ Complété
  • Alertes automatiques en cas d'échec - ✅ Complété
  • Tests automatisés de migration dans CI/CD - ✅ Complété
  • Validation plus poussée (détection de migrations manquantes) - ✅ Complété
  • Synchronisation depuis Liquibase - ✅ Complété
  • Dashboard de monitoring des migrations
  • Intégration avec le système de backup pour restaurer automatiquement

🔗 Références