Shopware-Worker stirbt beim Start: "Cannot find the "redis" extension nor the "predis/predis" package"
Die Storefront läuft normal. Admin normal, keine Fehlerseite, keine Beschwerde. Nur gehen keine Bestellbestätigungen mehr raus, der Suchindex bleibt auf dem Stand von vorgestern, und im Log stapelt sich derselbe Eintrag im Zwei-Minuten-Takt: Worker startet, kippt sofort um, Supervisor startet ihn neu.
Die Fehlermeldung
Error thrown while running command "messenger:consume --memory-limit=512M
--time-limit=300 async failed low_priority".
Message: "Cannot find the "redis" extension nor the "predis/predis" package."
[object] (Symfony\Component\Cache\Exception\CacheException(code: 0):
Cannot find the "redis" extension nor the "predis/predis" package.
at /var/www/shop/vendor/symfony/cache/Traits/RedisTrait.php:99)
Was dahintersteckt
Zwei Details in dieser Meldung lohnen genaues Lesen.
Erstens die Herkunft: Symfony\Component\Cache, nicht Messenger. RedisTrait::createConnection() prüft beim Aufbau der Verbindung, ob die Extension redis geladen ist oder die Klasse Predis\Client existiert. Ist beides nicht der Fall, fliegt die CacheException. Der Worker kommt also gar nicht bis zur Queue, er stirbt schon beim Bauen des Containers, weil irgendein Cache-, Session-, Lock-, Increment- oder Cart-Adapter auf eine redis://-DSN zeigt.
Zweitens der Widerspruch, über den alle stolpern: im Web funktioniert genau dieselbe Konfiguration. Weil es nicht dieselbe PHP-Installation ist. Unter Debian und Ubuntu werden Extensions pro SAPI freigeschaltet, /etc/php/8.3/mods-available/redis.ini wird getrennt nach fpm/conf.d/ und nach cli/conf.d/ verlinkt. Fehlt der zweite Symlink, hat FPM Redis und die Kommandozeile nicht.
Auf Servern mit Verwaltungsoberfläche kommt eine zweite Variante dazu, und die ist häufiger. Die Website läuft auf PHP 8.3, das nackte php auf der Shell ist aber die System-Default-Version, oft zwei Minor-Versionen älter. Der Supervisor-Eintrag ruft php bin/console messenger:consume ohne absoluten Pfad auf und erwischt damit ein PHP, für das nie jemand php-redis installiert hat.
Ein Bug ist das alles nicht. Shopware schreibt in der Cache-Doku ausdrücklich, dass die PHP-Redis-Extension installiert sein muss, bevor man die Redis-Adapter konfiguriert. Nur merkt man das Fehlen eben erst im Worker.
Prüfen, ob es wirklich das ist
Alles als der User ausführen, unter dem der Worker läuft. Nicht als root, sonst prüfst du eine andere Umgebung als die kaputte.
php -v
php -m | grep -i redis
php -i | grep 'Loaded Configuration File'
Wenn php -v eine andere Version zeigt als die, die im Panel für die Website eingestellt ist, hast du die Antwort schon. Danach die DSN suchen, die den Fehler auslöst:
grep -RIn "redis://" .env .env.local config/packages/ 2>/dev/null
bin/console debug:config shopware redis
debug:config funktioniert für den shopware.redis.connections-Block, den es seit 6.6.8.0 gibt. Bei älteren Installationen steckt die Verbindung meist als default_redis_provider in config/packages/framework.yaml oder direkt in der .env.local.
Und zum Schluss der Worker-Aufruf selbst:
grep -RIn "messenger:consume" /etc/supervisor/
Steht dort php bin/console statt /usr/bin/php8.3 bin/console, ist das dein Kandidat.
Die Lösung
Extension für die richtige Version nachinstallieren, nicht für irgendeine:
sudo apt install php8.3-redis
sudo phpenmod -v 8.3 redis
php8.3 -m | grep redis
Bei selbst gebautem PHP stattdessen pecl install redis und die extension=redis.so in die CLI-php.ini eintragen. FPM braucht danach einen Reload, die Kommandozeile nicht.
Dann den Aufruf festnageln. Absolute Pfade, beide:
[program:shopware_worker]
command=/usr/bin/php8.3 /var/www/shop/bin/console messenger:consume async low_priority failed --memory-limit=512M --time-limit=300
user=web1
numprocs=2
process_name=%(program_name)s_%(process_num)02d
autostart=true
autorestart=true
supervisorctl reread
supervisorctl update
supervisorctl status
Bleibt der Prozess jetzt länger als ein paar Sekunden im Status RUNNING, war es das.
Die Abkürzung, die dir jede zweite Suchtreffer-Seite anbietet, ist composer require predis/predis. Das ist ein Workaround, kein Fix, und er deckt nur die halbe Strecke ab. Predis reicht für Cache, Session und Lock Store. Der Redis-Transport des Messengers reicht nicht, der braucht laut Symfony-Doku die PHP-Extension ab Version 4.3 und akzeptiert Predis nicht. Wenn deine MESSENGER_TRANSPORT_DSN_* auf redis:// zeigen, kaufst du dir mit Predis nur einen anderen Fehler ein. Auf Hosting ohne eigene Extensions ist der ehrlichere Weg, die Transports vorübergehend auf doctrine:// zurückzustellen.
Wenn das nicht hilft
Der Fehler kommt auch bei Shops, in denen angeblich gar kein Redis konfiguriert ist. Für 6.6.9.0 gibt es dazu einen Issue-Report im Shopware-Repository (#5903), der ohne Ergebnis geschlossen wurde. In der Praxis steckt die DSN dann in einer Plugin-Konfiguration oder in einer config/packages/*.yaml, die beim Update aus einem Template mitgekommen ist. Die Grep-Zeile oben findet beides.
Zweiter Kandidat: ein Container-Cache in var/cache/, den die falsche PHP-Version gebaut hat. Einmal rm -rf var/cache/* und bin/console cache:warmup als der richtige User, mit dem richtigen Binary.
Und wenn mehrere Shops auf demselben Server liegen, prüfe jeden einzeln. Die Extension hängt an der PHP-Version, nicht am Server. Ein Shop auf 8.2 kann sauber laufen, während der auf 8.3 seit dem Versionswechsel im Panel keine Messages mehr verarbeitet.
Von außen sieht ein Shop in diesem Zustand gesund aus. Er antwortet, Bestellungen kommen rein, verarbeitet werden sie nicht, und wer nicht jeden Morgen durch die Logs scrollt, merkt es an der ersten Kundenmail. ShopSignal behält genau diese Stelle im Blick: Queue-Worker, Redis, OPcache und Elasticsearch, mit Alarm, wenn ein Worker in einer Neustartschleife hängt statt zu arbeiten.