Dateien, Datenbank, Queue & Assets
Ein Magento-Rollback ist mehr als ein Symlink-Wechsel. Datenbank, Queue-Nachrichten, Static Content und Elasticsearch-Indizes folgen eigenen Regeln. Wer nur Dateien zurückrollt, riskiert Inkonsistenzen, die schwieriger zu beheben sind als das ursprüngliche Problem.
Inhaltsverzeichnis
- 1. Die vier Schichten eines Magento-Rollbacks
- 2. Datei-Rollback: Symlink, Generated Code und Static Content
- 3. Datenbank-Rollback: Backup-Strategie und Expand-Contract
- 4. Queue-Zustand beim Rollback: Was mit RabbitMQ-Nachrichten passiert
- 5. Static Assets und Elasticsearch-Index nach dem Rollback
- 6. Entscheidungsbaum: Welche Rollback-Strategie passt?
- 7. Rollback-Strategien in der GitLab-Pipeline abbilden
- 8. Rollback-Szenarien im Vergleich
- 9. Zusammenfassung
- 10. Typische Fehler bei Rollback-Strategien
- 11. FAQ
1. Die vier Schichten eines Magento-Rollbacks
Ein Magento-System besteht aus vier unabhängigen Schichten, die beim Rollback unterschiedlich behandelt werden müssen. Die erste Schicht sind die Anwendungsdateien: PHP-Code, Hyvä-Templates, Composer-Abhängigkeiten, kompilierter DI-Code und Static Content. Diese Schicht ist per Symlink in Sekunden zurückrollbar. Die zweite Schicht ist die Datenbank: Magento-Konfiguration, Produktdaten, Bestellungen und alle Tabellen, die durch setup:upgrade verändert wurden. Diese Schicht ist nicht automatisch rollbackfähig.
Die dritte Schicht ist der Queue-Zustand: Nachrichten in RabbitMQ oder der MySQL-basierten Magento-Queue, die von Consumern des neuen Release eingestellt wurden und möglicherweise mit dem alten Code nicht verarbeitet werden können. Die vierte Schicht sind externe Dienste: Elasticsearch-Indizes, Redis-Cache-Inhalte und Varnish-Cache-Objekte. Diese Schicht ist oft die am wenigsten beachtete, kann aber nach einem Rollback zu schwer diagnostizierbaren Fehlern führen.
Die wichtigste Erkenntnis: Ein Rollback, der nur die Dateischicht berücksichtigt, ist für Releases ohne Datenbankmigrationen oder Queue-Änderungen ausreichend. Für Releases mit Datenbankmigrationen ist ein reiner Datei-Rollback gefährlich — der alte Code findet möglicherweise Tabellen oder Spalten, die er nicht erwartet, oder vermisst Spalten, die er braucht. Die Rollback-Strategie muss deshalb vor jedem Release explizit geplant werden.
2. Datei-Rollback: Symlink, Generated Code und Static Content
Der Datei-Rollback via Symlink-Wechsel ist der schnellste und sicherste Teil des Rollback-Prozesses. Das Release-Verzeichnis des vorherigen Stands ist vollständig vorhanden — mit Composer-Vendor, kompiliertem DI-Code und Static Content. Der Symlink-Wechsel ist atomar und dauert unter einer Sekunde. Cache-Flush danach ist Pflicht, weil Redis möglicherweise Objekte aus dem fehlerhaften Release gecacht hat.
Der generated/-Ordner enthält den von Magento kompilierten Dependency-Injection-Code. Dieser Code ist release-spezifisch und liegt im Release-Verzeichnis, nicht im shared-Bereich. Nach dem Rollback verwendet Magento automatisch den generierten Code des vorherigen Release — kein manueller Schritt notwendig. Gleiches gilt für pub/static/: Der Static Content des vorherigen Release liegt im vorherigen Release-Verzeichnis und wird nach dem Symlink-Wechsel wieder serviert.
#!/usr/bin/env bash
# scripts/rollback-files.sh — File-only rollback via symlink switch
# Safe for releases WITHOUT database migrations
set -euo pipefail
readonly APP_PATH="${DEPLOY_PATH:?}"
readonly ROLLBACK_TARGET="${1:-}"
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" bash -s <<SSH
set -euo pipefail
# Auto-detect previous release if no target specified
if [[ -z "${ROLLBACK_TARGET}" ]]; then
current="\$(basename \$(readlink -f ${APP_PATH}/current))"
TARGET="\$(ls -1d ${APP_PATH}/releases/*/ \
| sort -Vr | grep -v "\${current}/" | head -1 | xargs basename)"
else
TARGET="${ROLLBACK_TARGET}"
fi
echo "[ROLLBACK] Target release: \${TARGET}"
test -d "${APP_PATH}/releases/\${TARGET}" \
|| { echo "[FAIL] Release \${TARGET} not found"; exit 1; }
# Brief maintenance window for cache consistency
cd "${APP_PATH}/current"
bin/magento maintenance:enable --ip="${ALLOWED_IP:-127.0.0.1}" 2>/dev/null || true
# Atomic symlink switch — zero-downtime file rollback
ln -sfn "${APP_PATH}/releases/\${TARGET}" "${APP_PATH}/current"
echo "[OK] Switched to \${TARGET}"
# Full cache flush — mandatory after any rollback
cd "${APP_PATH}/current"
bin/magento cache:flush
echo "[OK] Cache flushed"
# Restart queue consumers to pick up new application path
supervisorctl restart magento-consumer:* 2>/dev/null \
|| systemctl restart magento-queue-consumer 2>/dev/null \
|| echo "[WARN] Could not restart queue consumers — manual restart required"
bin/magento maintenance:disable 2>/dev/null || true
echo "[OK] File rollback complete — now running \${TARGET}"
SSH
3. Datenbank-Rollback: Backup-Strategie und Expand-Contract
Der Datenbank-Rollback ist der schwierigste Teil eines Magento-Rollbacks. Magento-Datenbankmigrationen sind in der Standardimplementierung nicht reversibel — es gibt kein setup:downgrade. Wer nach einem Release zurückrollen will, das Datenbankmigrationen enthielt, hat drei Optionen: Ein vollständiges DB-Backup wiederherstellen (zeitaufwendig, Datenverlust seit dem Backup), ein Expand-Contract-Muster anwenden, oder die Migration manuell rückgängig machen.
Das Expand-Contract-Muster ist die eleganteste Lösung: Vor dem eigentlichen Release wird eine kompatible Datenbankänderung deployt, die sowohl der alte als auch der neue Code verarbeiten kann. Erst wenn der neue Code stabil läuft und kein Rollback mehr nötig ist, wird der "Contract" deployt, der die Übergangskonstrukte entfernt. Dieses Muster erfordert Disziplin bei der Entwicklung, macht aber Datenbankmigrationen vollständig rollbackfähig ohne Backup-Wiederherstellung.
# scripts/db-backup.sh — Create a timestamped database backup before deployment
# Run this BEFORE any release that includes database migrations
#!/usr/bin/env bash
set -euo pipefail
readonly BACKUP_DIR="${DEPLOY_PATH}/shared/backups/db"
readonly TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
readonly BACKUP_FILE="${BACKUP_DIR}/${CI_COMMIT_TAG:-manual}-${TIMESTAMP}.sql.gz"
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" bash -s <<SSH
set -euo pipefail
mkdir -p "${BACKUP_DIR}"
echo "[BACKUP] Creating database backup: ${BACKUP_FILE}"
mysqldump \
--single-transaction \
--quick \
--lock-tables=false \
--routines \
--triggers \
"${MAGENTO_DB_NAME}" \
| gzip -6 > "${BACKUP_FILE}"
backup_size="\$(du -sh "${BACKUP_FILE}" | cut -f1)"
echo "[OK] Backup created: ${BACKUP_FILE} (\${backup_size})"
# Keep only last 10 DB backups
ls -1t "${BACKUP_DIR}"/*.sql.gz 2>/dev/null | tail -n +11 | xargs rm -f 2>/dev/null || true
echo "[OK] Old backups cleaned up"
SSH
4. Queue-Zustand beim Rollback: Was mit RabbitMQ-Nachrichten passiert
Die Queue ist die am häufigsten vergessene Rollback-Schicht. Wenn ein neues Release für kurze Zeit aktiv war und dabei Nachrichten in RabbitMQ oder die Magento-MySQL-Queue eingestellt hat, müssen diese Nachrichten nach dem Rollback verarbeitet werden — vom alten Code. Das ist möglich, wenn das Nachrichtenformat kompatibel ist. Es ist problematisch, wenn das neue Release neue Nachrichtentypen oder veränderte Payload-Strukturen eingeführt hat.
Der praktische Umgang: Vor dem Rollback die Queue-Consumer stoppen, den Symlink wechseln, den Cache flushen und die Consumer mit dem alten Code neu starten. Nachrichten, die mit dem alten Code nicht verarbeitet werden können, landen in der Dead-Letter-Queue oder der Fehlertabelle. Diese müssen nach dem Rollback manuell bewertet werden. In Produktionssystemen mit hohem Queue-Durchsatz kann die Entscheidung auch lauten, die betroffene Queue kurzfristig zu leeren — mit dem Risiko, dass wenige Nachrichten verloren gehen — statt inkonsistente Nachrichten verarbeiten zu lassen.
5. Static Assets und Elasticsearch-Index nach dem Rollback
Static Content liegt im Release-Verzeichnis und wechselt automatisch mit dem Symlink. Das bedeutet: Nach dem Rollback serviert Nginx sofort den Static Content des vorherigen Release — ohne manuellen Eingriff, ohne Cache-Warmup. Browser-seitig gecachte Assets des fehlerhaften Release sind ein kurzzeitiges Problem, das sich durch Cache-Busting-Mechanismen (Asset-Hashes in Dateinamen) von selbst löst.
Der Elasticsearch-Index hingegen ist nicht release-spezifisch. Er wird nicht zurückgerollt, wenn der Symlink wechselt. Wenn das neue Release Änderungen am Index-Mapping oder an den Indexierungs-Routinen hatte, kann der Index nach dem Rollback inkompatibel mit dem alten Code sein. In diesem Fall muss eine vollständige Reindexierung durchgeführt werden: bin/magento indexer:reindex catalogsearch_fulltext. Bei großen Katalogen dauert das mehrere Minuten bis Stunden — ein wichtiger Faktor bei der Rollback-Planung.
6. Entscheidungsbaum: Welche Rollback-Strategie passt?
Die richtige Rollback-Strategie hängt davon ab, was das Release verändert hat. Vor jedem Release sollte diese Entscheidung bewusst getroffen und dokumentiert werden — nicht erst wenn der Rollback nötig ist. Die folgende Logik hilft bei der Einordnung:
Wenn das Release keine Datenbankmigrationen und keine Queue-Änderungen enthält, ist der reine Datei-Rollback via Symlink ausreichend. Wenn das Release kompatible Datenbankmigrationen (additiv, ohne Spalten zu entfernen) enthält, ist der Datei-Rollback mit anschließendem DB-Backup als Sicherheitsnetz ausreichend. Wenn das Release inkompatible Datenbankmigrationen (Spalten entfernen, Typen ändern, Breaking Changes) enthält, muss vor dem Deployment ein vollständiges DB-Backup gemacht werden, und der Rollback umfasst Datei-Rollback plus DB-Restore.
# .gitlab-ci.yml — Database backup job before migration-heavy releases
db:backup:before-migrate:
stage: deploy
script:
- ./scripts/db-backup.sh
rules:
# Only run when the release is tagged as containing DB migrations
# Set CONTAINS_DB_MIGRATIONS=true in GitLab pipeline variables when needed
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/ && $CONTAINS_DB_MIGRATIONS == "true"
when: always
# This job must succeed before the deploy job runs
allow_failure: false
rollback:with-db-restore:
stage: rollback
script:
- |
# Full rollback: files + database restore
BACKUP_FILE="${DEPLOY_PATH}/shared/backups/db/${RESTORE_BACKUP_FILE}"
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" bash -s <<'SSH'
set -euo pipefail
# Step 1: stop consumers
supervisorctl stop magento-consumer:* 2>/dev/null || true
# Step 2: file rollback
ln -sfn "${DEPLOY_PATH}/releases/${ROLLBACK_TARGET}" "${DEPLOY_PATH}/current"
# Step 3: database restore
zcat "${BACKUP_FILE}" | mysql "${MAGENTO_DB_NAME}"
echo "[OK] Database restored from ${BACKUP_FILE}"
# Step 4: cache and search reindex
cd "${DEPLOY_PATH}/current"
bin/magento cache:flush
bin/magento indexer:reindex
# Step 5: restart consumers
supervisorctl start magento-consumer:* 2>/dev/null || true
SSH
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
when: manual
allow_failure: true
7. Rollback-Strategien in der GitLab-Pipeline abbilden
Die GitLab-Pipeline bildet die verschiedenen Rollback-Strategien als separate manuelle Jobs ab. Es gibt mindestens zwei Jobs: einen für den einfachen Datei-Rollback und einen für den vollständigen Rollback mit DB-Restore. Welcher Job ausgelöst wird, entscheidet das Deployment-Team im Störfall — basierend auf der vorab dokumentierten Information, ob das Release Datenbankmigrationen enthielt.
Diese Information muss in der Deployment-Dokumentation oder als Pipeline-Variable pro Release festgehalten sein. Eine praktische Konvention: Releases mit Datenbankmigrationen werden mit einem -migrate-Suffix oder einer Pipeline-Variable CONTAINS_DB_MIGRATIONS=true gekennzeichnet. Der Rollback-Job für DB-Releases ist dann nur sichtbar, wenn diese Variable gesetzt ist. Das verhindert versehentliche DB-Rollbacks für Releases, die nur Code-Änderungen enthalten.
8. Rollback-Szenarien im Vergleich
Unterschiedliche Release-Typen erfordern unterschiedliche Rollback-Strategien. Der Überblick zeigt, welche Strategie für welches Szenario geeignet ist und welche Nebeneffekte berücksichtigt werden müssen.
| Release-Typ | Rollback-Strategie | Dauer | Datenverlustrisiko |
|---|---|---|---|
| Nur Code/Templates | Symlink + Cache-Flush | < 2 Minuten | Keines |
| Additive DB-Migration | Symlink + Cache + Backup als Netz | < 3 Minuten | Gering (neue Daten in neuer Spalte) |
| Breaking DB-Migration | Symlink + DB-Restore | 30–90 Minuten | Alle Daten seit Backup verloren |
| Queue-Format-Änderung | Symlink + Queue leeren + Consumer restart | < 5 Minuten | Offene Queue-Nachrichten verloren |
| ES-Index-Änderung | Symlink + Reindexierung | 10 Min. – mehrere Stunden | Keines (Index wird neu aufgebaut) |
9. Zusammenfassung
Ein vollständiger Rollback für Magento berücksichtigt vier Schichten: Dateien, Datenbank, Queue und externe Dienste. Der Datei-Rollback via Symlink ist der einfachste und schnellste Teil und für Releases ohne Datenbankmigrationen vollständig ausreichend. Für Releases mit additiven Migrationen ist ein DB-Backup als Sicherheitsnetz sinnvoll. Für Releases mit Breaking Changes in der Datenbank ist ein vollständiger DB-Restore die einzige sichere Option — mit dem Risiko von Datenverlust seit dem Backup.
Die wichtigste Praxis ist die Rollback-Klassifizierung vor jedem Release: Was enthält dieses Release, und welche Rollback-Strategie ist deshalb nötig? Diese Information muss dokumentiert und für das gesamte Team sichtbar sein. GitLab-Pipeline-Variablen bieten eine pragmatische Möglichkeit, diese Klassifizierung maschinenlesbar zu machen und die richtigen Rollback-Jobs zu aktivieren.
Rollback-Strategien für Magento — Das Wichtigste auf einen Blick
Vier Schichten
Dateien (Symlink), Datenbank (Backup/Restore), Queue (Stop/Restart) und externe Dienste (Cache, ES-Index). Jede Schicht hat eigene Rollback-Anforderungen.
Entscheidung vor dem Release
Rollback-Strategie vor jedem Release klassifizieren. Enthält es DB-Migrationen? Queue-Änderungen? Diese Antwort bestimmt, welche Schritte im Störfall nötig sind.
DB-Backup als Pflicht
Vor jedem Release mit Datenbankmigrationen ein vollständiges DB-Backup anlegen. Ohne Backup kein echter Rollback-Pfad für DB-Änderungen.
Queue und ES separat
Queue-Consumer nach Rollback immer neu starten. Elasticsearch bei Index-Änderungen vollständig reindexieren. Beide Schritte aus dem Rollback-Skript automatisieren.
10. Typische Fehler bei Rollback-Strategien
Der gefährlichste Fehler ist ein Datei-Rollback bei einem Release, das Breaking-DB-Migrationen enthielt. Das Ergebnis: Der alte Code läuft mit der neuen Datenbankstruktur. Magento versucht, auf Spalten zuzugreifen, die entfernt wurden, oder ignoriert Spalten, die noch nicht da sein sollten. Die Fehler sind subtil und manchmal erst unter Last sichtbar — wenn zum Beispiel ein Checkout-Prozess auf eine nicht mehr existierende Spalte in sales_order zugreift.
Ein zweiter Fehler ist das Rollback ohne anschließenden Cache-Flush. Redis hält Objekte im Cache, die mit dem alten Code möglicherweise inkompatibel sind — insbesondere wenn neue Cache-Tags oder veränderte Objekt-Strukturen im fehlerhaften Release eingeführt wurden. Der Cache-Flush nach dem Rollback ist immer Pflicht, auch wenn er für Releases ohne Caching-Änderungen scheinbar unnötig ist. Die Kosten eines Cache-Flushes (kurzer Performance-Einbruch) sind minimal gegenüber den Kosten inkonsistenter Cache-Daten.