Oft möchte man zeitintensive Datenverarbeitung vom Web-Frontend entkoppeln. PHP ist hier leider keine große Hilfe – allerdings geht das relativ einfach mit dem “Umweg” über eine Message Queue. Die Message Queue agiert hierbei als persistenter FIFO Queue: Sobald die Nachricht übermittelt ist, kann das Frontend schon weitermachen. Die Nachricht ist gespeichert und kann jederzeit abgeholt und verarbeitet werden. Im Hintergrund benötigen wir zusätzlich einen Service, der die Nachrichten verlässlich sequentiell abarbeitet: Ich möchte hier ebenfalls mit PHP arbeiten.
Voraussetzung
Solche Lösungen lassen sich auf Shared Hosting Lösungen nur sehr schlecht umsetzen, da man auf seinem Server Software installieren muß: Eine (in meinem Falle) Debian-VPS mit root Rechten muss es schon sein. Unter z.B. https://www.hosteurope.de/Server/Virtual-Server/ bekommt man so eine VPS schon ab EUR 9.99 / Monat.
beanstalkd installieren
Als erstes installieren wir beanstalkd – eine Open Source Message Queue Lösung:
# sudo apt-get update # sudo apt-get install beanstalkd
Die zugehörige Konfigurationsdatei findet sich unter /etc/default/beanstalkd – Hier können IP und Port konfigurieren, auf denen gehorcht wird. Per Default horch beanstalkd auf 127.0.0.1:11300
Optional: Beanstalkd Console installieren
Optional, aber sehr empfehlenswert: Einen eigenen VHost einrichten und die Beanstalkd Console installieren, die man unter https://github.com/ptrofimov/beanstalk_console finden kann. Mit Hilfe dieser Web-App kann man jederzeit die Queue einsehen, Nachrichten lesen, erstellen oder auch löschen – Sehr hilfreich.
Einen PHP Consumer erstellen
Grundsätzlich benötigen wir ein kleines Programm, dass auf neue Nachrichten in der Queue horcht und diese abarbeitet bzw. “konsumiert”.
Dazu erstellen wir etwas ganz Einfaches: Der Consumer horcht auf die Queue – Der Inhalt neuer Nachrichten wird in ein Logfile geschrieben.
Wir nutzen die composer Library “Pheanstalk\Pheanstalk“:
<?php use Pheanstalk\Pheanstalk; /** * small consumer * @see /lib/systemd/system/beanstalk-consumer.service * @see https://medium.com/@benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6 * @author jjarolim, adwerba */ require_once __DIR__ . '/vendor/autoload.php'; $pheanstalk = new Pheanstalk('127.0.0.1'); while ($job = $pheanstalk->watch('default')->reserve()) { file_put_contents(__DIR__.'/consumer.log', $job->getData()."\n", FILE_APPEND); $pheanstalk->delete($job); }
Service erstellen
Damit der Consumer auch verlässlich im Hintergund läuft und auf neue Nachrichten reagiert, erstellen wir einen Systemd Service: Systemd kümmert sich darum, dass der Consumer verlässlich läuft bzw. neu gestartet wird, sollte er sich aufhängen.
Dazu erstellen wir das File beanstalk-consumer.service unter /lib/systemd/system:
[Unit] Description=Beanstalk Consumer Demo Service After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=always RestartSec=1 User=www-data ExecStart=/usr/bin/env php /path/to/consumer.php [Install] WantedBy=multi-user.target
Service starten / stoppen
Schlußendlich starten wir den neuen Service und alles läuft:
# systemctl start beanstalk-consumer
Ab jetzt kann man neue Nachrichten in die Queue schicken: Der Consumer reagiert zeitnah und verarbeitet brav alles.