Web, Worker, Cron, Queue
Ein einzelner Web-Server ist selten die Realität in Magento-Produktionssystemen. Wenn Web-Server, Worker-Prozesse, Cron-Jobs und Queue-Consumer auf verschiedene Hosts verteilt sind, muss die GitLab-Pipeline diese Komplexität koordinieren – ohne Race Conditions, verwaiste Prozesse oder Teildeployments.
Inhaltsverzeichnis
- 1. Das Multi-Server-Problem bei Magento-Deployments
- 2. Servertypen und ihre Deployment-Anforderungen
- 3. Deployment-Sequenz: wer zuerst, wer zuletzt
- 4. Web-Server-Deployment: Rolling oder parallel
- 5. Worker-Prozesse: sauber stoppen, neu starten
- 6. Cron-Jobs während des Deployments kontrollieren
- 7. Queue-Consumer: Draining und Restart
- 8. Sequenzierungsstrategien im Vergleich
- 9. Zusammenfassung
- 10. Typische Fehler bei Multi-Server-Deployments
- 11. FAQ
1. Das Multi-Server-Problem bei Magento-Deployments
In einem Einzel-Server-Setup ist die Deployment-Logik verhältnismäßig einfach: Artefakt übertragen, Symlink wechseln, Magento-Kommandos ausführen, Cache leeren. In einem Multi-Server-Setup mit getrennten Web-Servern, Worker-Hosts, Cron-Servern und Queue-Consumer-Prozessen wird die Koordination zu einer eigenständigen Herausforderung. Wer das Deployment eines Web-Servers abschließt, während auf dem Worker-Host noch der alte Code läuft, erzeugt eine Situation, in der beide Codebasen gleichzeitig auf dieselbe Datenbank zugreifen – möglicherweise mit unterschiedlichen Erwartungen an das Datenbankschema.
GitLab-Pipelines können diese Koordination übernehmen, weil Jobs sequenziell oder parallel ausgeführt werden können und Abhängigkeiten zwischen Jobs explizit definierbar sind. Die Kunst liegt darin, die richtige Reihenfolge zu definieren: Welcher Servertyp wird zuerst updated? Wann werden Queue-Consumer gestoppt? Wann werden Cron-Jobs wieder freigegeben? Diese Fragen müssen im Pipeline-Design beantwortet werden, bevor das erste Deployment ausgeführt wird.
Magento macht Multi-Server-Deployments besonders anspruchsvoll, weil mehrere Prozesstypen auf denselben Code angewiesen sind: Der Webserver verarbeitet HTTP-Requests, Consumer-Prozesse verarbeiten RabbitMQ-Messages, Cron-Jobs führen zeitgesteuerte Tasks aus und Worker wie Indexer können im Hintergrund laufen. Jeder dieser Prozesstypen hat unterschiedliche Anforderungen an den Deployment-Moment und muss entsprechend behandelt werden.
2. Servertypen und ihre Deployment-Anforderungen
Web-Server (Nginx/PHP-FPM) verarbeiten eingehende HTTP-Requests. Ihr Deployment muss so schnell wie möglich erfolgen und darf bestehende Verbindungen nicht hart unterbrechen. Rolling Deployments – zuerst ein Server aus dem Load Balancer nehmen, deployen, zurück – minimieren den Impact auf laufende Requests. Worker-Server führen langfristige Hintergrundprozesse aus, die nicht durch ein Deployment unterbrochen werden sollten. Sie müssen kontrolliert gestoppt werden, bevor der neue Code aktiviert wird, und danach neu gestartet werden.
Cron-Server führen zeitgesteuerte Aufgaben aus. Während des Deployments sollten keine Cron-Jobs ausgeführt werden, die sowohl auf alten als auch auf neuen Code-Artefakten aufbauen könnten. Der einfachste Ansatz: Magento-Cron während des Deployments deaktivieren und danach wieder aktivieren. Queue-Consumer verarbeiten Messages aus einer Message Queue wie RabbitMQ. Sie müssen vor dem Deployment-Moment alle laufenden Messages abarbeiten (Draining), dann gestoppt werden und nach dem Deployment mit dem neuen Code neu gestartet werden.
# Multi-server deployment configuration
# Servers: web01, web02 (load balanced), worker01, cron01
stages:
- build
- test
- package
- pre-deploy # Stop consumers, disable cron
- deploy-web # Deploy to web servers
- deploy-worker # Deploy to worker servers
- post-deploy # Run Magento commands, restart services
- verify # Smoke tests on all servers
- rollback # Manual rollback across all servers
variables:
WEB_HOSTS: "web01.mironsoft.de web02.mironsoft.de"
WORKER_HOST: "worker01.mironsoft.de"
CRON_HOST: "cron01.mironsoft.de"
DEPLOY_USER: "deploy"
DEPLOY_PATH: "/var/www/magento"
3. Deployment-Sequenz: wer zuerst, wer zuletzt
Die Deployment-Sequenz in einem Multi-Server-Setup muss klar definiert sein. Die empfohlene Reihenfolge für Magento: Zuerst die Pre-Deploy-Stage – Cron-Jobs deaktivieren, Queue-Consumer stoppen und laufende Messages drainieren. Danach die Web-Server deployen, idealerweise in Rolling-Reihenfolge, damit immer mindestens ein Server für den Load Balancer verfügbar bleibt. Anschließend die Worker-Server und den Cron-Server deployen. Danach die Magento-Kommandos ausführen – setup:upgrade, cache:flush – und die Services neu starten. Am Ende die Verify-Stage mit Smoke Tests auf allen Server-Typen.
Diese Sequenz stellt sicher, dass niemals zwei verschiedene Code-Versionen gleichzeitig auf dieselbe Datenbank zugreifen. Die Pre-Deploy-Stage ist dabei der kritischste Schritt: Bevor der erste Byte neuer Code auf einen Server übertragen wird, müssen alle Hintergrundprozesse, die mit der Datenbank interagieren, kontrolliert gestoppt sein. Wer diesen Schritt überspringt, riskiert inkonsistente Datenbankzustände, die durch Race Conditions entstehen.
4. Web-Server-Deployment: Rolling oder parallel
Für Web-Server gibt es zwei Strategien: Paralleles Deployment – alle Web-Server gleichzeitig updaten – und Rolling Deployment – Server nacheinander updaten und dabei jeden kurz aus dem Load Balancer nehmen. Paralleles Deployment ist einfacher zu implementieren, aber es gibt für einen kurzen Moment keinen verfügbaren Web-Server. Rolling Deployment ist komplexer, aber der Shop bleibt durchgehend erreichbar. Für Magento-Produktionssysteme ist Rolling Deployment die Empfehlung, weil Magento nicht schnell genug startet, um einen kurzen Totalausfall akzeptabel zu machen.
GitLab kann Rolling Deployments nicht nativ orchestrieren – dafür ist ein Deployment-Tool wie Deployer oder ein benutzerdefiniertes Shell-Skript notwendig, das in einem GitLab-Job ausgeführt wird. Das Skript nimmt einen Server aus dem Load Balancer, deployt, wartet auf PHP-FPM-Restart und fügt den Server zurück ein, bevor es mit dem nächsten Server fortfährt. Der kritische Parameter ist die Wartezeit nach dem PHP-FPM-Reload – zu kurz, und laufende Requests werden unterbrochen; zu lang, und das Deployment dauert unnötig lange.
deploy:web-servers:
stage: deploy-web
image: alpine:3.19
before_script:
- apk add --no-cache openssh-client rsync bash
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
script:
# Rolling deployment: one web server at a time
- |
for HOST in $WEB_HOSTS; do
echo "==> Deploying to web server: $HOST"
RELEASE_ID="$(date +%Y%m%d-%H%M%S)"
RELEASE_PATH="${DEPLOY_PATH}/releases/${RELEASE_ID}"
ssh "${DEPLOY_USER}@${HOST}" "mkdir -p ${RELEASE_PATH}"
rsync -az --delete --exclude='.git' --exclude='var/' \
./ "${DEPLOY_USER}@${HOST}:${RELEASE_PATH}/"
ssh "${DEPLOY_USER}@${HOST}" "
ln -sfn ${DEPLOY_PATH}/shared/app/etc/env.php ${RELEASE_PATH}/app/etc/env.php
ln -sfn ${DEPLOY_PATH}/shared/pub/media ${RELEASE_PATH}/pub/media
ln -sfn ${RELEASE_PATH} ${DEPLOY_PATH}/current
sudo systemctl reload php8.4-fpm
"
echo "${HOST}: deployed ${RELEASE_ID}"
# Brief wait to allow PHP-FPM to reload gracefully
sleep 5
done
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
5. Worker-Prozesse: sauber stoppen, neu starten
Worker-Prozesse auf dedizierten Worker-Servern müssen vor dem Deployment sauber gestoppt werden. Das Stoppen darf nicht hart (SIGKILL) erfolgen, weil laufende Operationen sonst inkonsistent abgebrochen werden. Der korrekte Ablauf ist SIGTERM senden, dann warten, bis der Prozess regulär beendet hat, und erst danach das Deployment fortsetzen. Für Supervisor-verwaltete Worker-Prozesse erfolgt das über supervisorctl stop all vor dem Deployment und supervisorctl start all danach.
Nach dem Deployment des neuen Codes werden die Worker neu gestartet. Dabei ist es wichtig, dass der neue Code vollständig übertragen und der Symlink gesetzt wurde, bevor die Worker gestartet werden – sonst laufen sie mit einem Mix aus altem und neuem Code. Die Startup-Sequenz im Post-Deploy-Job muss diese Abhängigkeit explizit abbilden: Worker starten erst, wenn das Deployment aller Server abgeschlossen ist.
6. Cron-Jobs während des Deployments kontrollieren
Magento-Cron-Jobs werden von zwei Prozessen gesteuert: dem System-Cron, der regelmäßig bin/magento cron:run aufruft, und den Magento-internen Cron-Gruppen. Während des Deployments sollte der Magento-Cron deaktiviert werden, um zu verhindern, dass Cron-Jobs in einem Moment laufen, in dem der Code gerade gewechselt wird. Das einfachste Mittel: Den System-Cron-Eintrag während des Deployments auskommentieren und danach wieder aktivieren.
Ein robusterer Ansatz nutzt Magento-Locks: bin/magento cron:install --force überschreibt die Crontab nach dem Deployment mit dem korrekten Eintrag. Vor dem Deployment kann mit bin/magento cron:remove der Cron-Eintrag entfernt werden. Dieser Ansatz ist zuverlässiger als manuelles Bearbeiten der Crontab, weil er idempotent ist und bei jedem Deployment den Cron-Eintrag garantiert im korrekten Zustand hinterlässt. Laufende Cron-Jobs, die beim Deployment gerade aktiv sind, sollten über einen Timeout-Mechanismus abgewartet werden – typischerweise maximal fünf Minuten.
pre-deploy:stop-services:
stage: pre-deploy
image: alpine:3.19
before_script:
- apk add --no-cache openssh-client bash
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
script:
# Stop queue consumers on worker server
- ssh "${DEPLOY_USER}@${WORKER_HOST}" "
sudo supervisorctl stop all
echo 'Queue consumers stopped'
"
# Disable Magento cron on cron server
- ssh "${DEPLOY_USER}@${CRON_HOST}" "
cd ${DEPLOY_PATH}/current
bin/magento cron:remove
echo 'Magento cron removed'
"
# Wait for running cron jobs to finish (max 5 minutes)
- |
TIMEOUT=300
ELAPSED=0
while ssh "${DEPLOY_USER}@${CRON_HOST}" "pgrep -f 'cron:run' > /dev/null 2>&1"; do
if [ $ELAPSED -ge $TIMEOUT ]; then
echo "Timeout waiting for cron jobs to finish"
exit 1
fi
sleep 10
ELAPSED=$((ELAPSED + 10))
done
echo "All cron jobs finished"
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
7. Queue-Consumer: Draining und Restart
Queue-Consumer, die RabbitMQ-Messages verarbeiten, müssen vor dem Deployment drainiert werden – das bedeutet, alle aktuell in Verarbeitung befindlichen Messages sollen abgeschlossen werden, bevor der Consumer gestoppt wird. Magento bietet dafür den Parameter --max-messages für bin/magento queue:consumers:start: Wenn ein Consumer mit --max-messages=1000 gestartet wird, beendet er sich selbst nach 1000 Messages. In Kombination mit Supervisor, der den Consumer automatisch neu startet, führt das zu regelmäßigen kontrollierten Neustarts.
Für das Deployment-Draining gibt es zwei Ansätze: Entweder wartet man, bis alle laufenden Consumer-Prozesse ihre aktuelle Message abgeschlossen haben und stoppt sie dann, oder man sendet dem Consumer-Prozess ein Signal, das ihn anweist, die Queue zu drainieren und sich danach zu beenden. Supervisor unterstützt supervisorctl stop mit SIGTERM, was bei korrekt implementierten Magento-Consumern das Draining auslöst. Wer eigene Consumer implementiert, muss sicherstellen, dass sie auf SIGTERM korrekt reagieren.
8. Sequenzierungsstrategien im Vergleich
Es gibt verschiedene Ansätze, wie Multi-Server-Deployments sequenziert werden können. Die Wahl hängt von der Systemarchitektur, dem akzeptierten Downtime-Budget und der Komplexität der Pipeline ab. Für Magento-Produktionssysteme haben sich drei Hauptstrategien etabliert.
| Strategie | Vorgehen | Downtime-Risiko | Geeignet für |
|---|---|---|---|
| Parallel (alle gleichzeitig) | Alle Server in einem Schritt updaten | Kurzer Totalausfall möglich | Dev/Staging, kleine Teams |
| Rolling (nacheinander) | Server einzeln updaten, Load Balancer anpassen | Kein Ausfall bei korrekter LB-Config | Production mit Load Balancer |
| Blue/Green | Parallele Infrastruktur, Umschalten nach Verify | Null Downtime, sofortiger Rollback | Hochverfügbarkeit, Kubernetes |
| Sequenziell mit Pre/Post | Services stoppen, deployen, Services starten | Kurzes Wartungsfenster | Worker, Cron, Queue-Consumer |
In der Realität werden diese Strategien kombiniert: Web-Server erhalten ein Rolling Deployment ohne Downtime, während Worker und Cron-Server sequenziell mit einem kurzen kontrollierten Stopp behandelt werden. Diese Kombination ist für die meisten Magento-Produktionssysteme der richtige Ansatz – sie maximiert die Verfügbarkeit für Endnutzer und minimiert das Risiko inkonsistenter Datenbankzustände durch parallel laufende alte und neue Hintergrundprozesse.
9. Zusammenfassung
Multi-Server-Deployments mit GitLab für Magento erfordern eine klare Sequenzierungsstrategie, die alle Servertypen berücksichtigt: Web-Server mit Rolling Deployment, Worker-Prozesse mit kontrolliertem Stop und Restart, Cron-Jobs mit temporärer Deaktivierung und Queue-Consumer mit Draining. Die Pre-Deploy-Stage ist dabei der kritischste Schritt – sie stellt sicher, dass alle Hintergrundprozesse gestoppt sind, bevor neuer Code aktiviert wird. Nur so kann verhindert werden, dass alter und neuer Code gleichzeitig auf dieselbe Datenbank zugreifen.
GitLab-Pipelines sind gut geeignet, um diese Koordination abzubilden: Stages definieren die Reihenfolge, Job-Abhängigkeiten stellen sicher, dass kein Deploy-Job startet, bevor der Pre-Deploy abgeschlossen ist, und manuelle Jobs für den Rollback geben dem Team die Kontrolle zurück, wenn etwas nicht wie erwartet funktioniert. Der größte Hebel liegt in der Planung: Wer die Sequenz vor dem ersten Deployment dokumentiert und in Staging übt, erspart sich hektische Koordination im Produktionsfall.
Multi-Server-Deployment — Das Wichtigste auf einen Blick
Pre-Deploy-Stage
Queue-Consumer stoppen, Cron deaktivieren, laufende Jobs abwarten – bevor der erste Byte neuer Code übertragen wird.
Web-Server-Strategie
Rolling Deployment mit Load-Balancer-Integration – immer mindestens ein Server verfügbar. Kein Totalausfall für Endnutzer.
Worker und Cron
SIGTERM-basierter Stop, auf sauberes Ende warten, nach Deployment neu starten. Cron via bin/magento cron:remove und cron:install steuern.
Queue-Consumer
Draining über SIGTERM, Supervisor-Stop, nach Deployment mit neuem Code neu starten. max-messages-Parameter für kontrollierte Neustarts nutzen.
10. Typische Fehler bei Multi-Server-Deployments
Der häufigste Fehler bei Multi-Server-Deployments ist das Fehlen der Pre-Deploy-Stage. Wer direkt mit dem Deployen der Web-Server beginnt, ohne Worker und Consumer zu stoppen, riskiert Race Conditions: Der Web-Server verarbeitet Bestellungen mit neuem Code und schreibt in die Datenbank, während der Worker-Prozess noch mit altem Code läuft und dasselbe Datenbankschema anders interpretiert. Die Folgen können inkonsistente Bestelldaten, fehlschlagende Indexer-Jobs oder gesperrte Datenbankzeilen sein.
Ein weiterer häufiger Fehler ist das Vergessen des Cron-Deaktivierungsschritts. Wenn während des Deployments ein Cron-Job startet – zum Beispiel der Magento-Cron alle fünf Minuten – kann er auf einen Zustand treffen, in dem der Symlink gerade umgeschaltet wird oder die Shared-Dateien noch nicht verlinkt sind. Das Ergebnis ist ein fehlschlagender Cron-Job, der im Fehlerfall falsche Alarme auslöst oder Datenbankeinträge in einem inkonsistenten Zustand hinterlässt. bin/magento cron:remove vor dem Deployment und bin/magento cron:install danach ist das einfachste und zuverlässigste Mittel dagegen.