Verschwenden Sie nicht Ihre Zeit mit Warten - lassen Sie Symfony Messenger die Arbeit im Hintergrund in Ihrer Pimcore-Anwendung erledigen.
Symfony Messenger ist eine Komponente, die Anwendungen bei der Verwaltung von Warteschlangen hilft, insbesondere wenn sie mit anderen Systemen kommunizieren oder Arbeit an verschiedene Dienste delegieren. Da Pimcore alle bestehenden asynchronen Warteschlangen durch Symfony Messenger ersetzt hat, ist es sogar noch einfacher, es in Ihr Projekt zu implementieren.
Nehmen wir an, es gibt ein Gewinnspielformular auf Ihrer Website, sogar ein sehr einfaches mit drei Feldern:
Und es ist sehr ähnlich wie bei der Klassendefinition, welche Objekte in Pimcore gespeichert werden.
Der Controller bearbeitet das Kontaktformular, speichert das Objekt in der Datenbank und sendet eine E-Mail mit den genauen Daten.
<?php |
namespace App\Controller; |
verwenden Sie App\Form\Type\CompetitionApplicationType; |
use Carbon\Carbon; |
use Exception; |
use Pimcore\Controller\FrontendController; |
use Pimcore\Mail; |
use Pimcore\Model\DataObject\CompetitionApplication; |
use Pimcore\Model\DataObject\Service; |
use Pimcore\Translation\Translator; |
use Symfony\Component\HttpFoundation\Request; |
use Symfony\Component\HttpFoundation\Response; |
class DefaultController erweitert FrontendController |
{ |
public function defaultAction(Request $request, Translator $translator): Response |
{ |
$competitionApplication = new CompetitionApplication(); |
$form = $this->createForm(CompetitionApplicationType::class, $competitionApplication); |
$form->handleRequest($request); |
if ($form->isSubmitted() && $form->isValid()) { |
$competitionApplication = $form->getData(); |
try { |
$this->processCompetitionApplication($competitionApplication); |
$this->addFlash('success', $translator->trans('form.competition-application.success')); |
} catch (Exception $e) { |
$this->addFlash('error', $translator->trans('form.competition-application.error')); |
} |
} |
return $this->render('default/default.html.twig', [ |
'form' => $form->createView() |
]); |
} |
/** |
* @throws Exception |
*/ |
private function processCompetitionApplication(CompetitionApplication $competitionApplication): void |
{ |
$now = Carbon::now(); |
$competitionApplication->setDate($now); |
$competitionApplication->setKey($now->timestamp); |
$competitionApplication->setPublished(true); |
$competitionApplication->setParent(Service::createFolderByPath($now->format('/Y/m/d'))); |
$competitionApplication->save(); |
$mail = new Mail(); |
$mail->an('competition@example.com'); |
$mail->subject('Neue Bewerbung für ein Auswahlverfahren'); |
$mail->html("<p>Vorname: </p><p>E-Mail: </p><p>Nachricht: </p>"); |
$mail->setParams([ |
'vorname' => $competitionApplication->getFirstname(), |
'email' => $competitionApplication->getEmail(), |
'message' => $competitionApplication->getMessage(), |
]); |
$mail->send(); |
} |
} |
Nun, das funktioniert bereits gut, aber gibt es einen noch besseren Weg?
Vor der Implementierung von Symfony Messenger dauerte die Verarbeitung des Kontaktformulars, das Speichern des Objekts und das Senden einer E-Mail etwa 4 Sekunden.
Und warum? Der Hauptgrund ist die Kommunikation mit dem SMTP-Server, der für den Versand von E-Mails zuständig ist. Es gibt einen großen Unterschied in der Verarbeitungszeit, wenn man diesen Teil überspringt und nur das Objekt speichert. Der Unterschied ist spürbar und kann sich auf die Leistung und Benutzerfreundlichkeit der Website auswirken.
Das ist genau der Grund, warum Symfony Messenger geschaffen wurde und Pimcore die bestehenden asynchronen Warteschlangen ersetzt hat. Es müssen zwei Klassen erstellt werden:
Anstatt das Objekt zu speichern und eine E-Mail zu senden, rufen Sie nun im ControllerCompetitionApplicationMessage auf, indem Sie dasMessageBusInterface in die Methode einfügen, die für die Bearbeitung von Anfragen zuständig ist. Denken Sie auch hier daran, Ihreservices.yaml-Konfiguration zu ändern und Ihrem Handler mitzuteilen, dass er jetzt ein Message-Handler ist.
Das ist sehr aufregend. Aber es gibt eine große Enttäuschung, weil das Formular immer noch etwa 4 Sekunden lang bearbeitet wird.
Standardmäßig führt Symfony Messenger Aufgaben sofort aus. Um ihn asynchron zu machen, muss man die Konfigurationsdateiconfig/packages/messenger.yaml erstellen, in der definiert wird, wie die Nachricht ausgeführt und behandelt werden soll. Die UmgebungsvariableMESSENGER_TRANSPORT_DSN gibt an, welcher Transporter für die Warteschlangen zuständig sein wird. Das kann Redis, RabbitMQ oder sogar eine Datenbank sein. Damit die Warteschlangenaufgaben mit cron oder supervisord zyklisch korrekt ausgeführt werden, muss der Befehlphp bin/console messenger:consume async ausgeführt werden.
Durch die asynchrone Verarbeitung unseres Formulars mit Symfony Messenger können wir eine deutliche Leistungssteigerung feststellen.
Durch die Verwendung eines Systems zur Steuerung von Prozessen wie supervisord wird die Logik, die innerhalb unserer Aufgabe ausgeführt wird, dem für die Verarbeitung der Prozesse zuständigen Dienst und nicht der Anwendung aufgebürdet, was bei hohem Datenverkehr und einer großen Anzahl von Prozessen zu einer enormen Steigerung der wahrgenommenen Leistung und Stabilität führen kann.
Ein weiterer Vorteil ist, dass bei einem Ausfall des SMTP-Dienstes die Aufgabe nicht als abgeschlossen markiert wird und drei Versuche unternommen werden müssen, um sie neu zu starten. Würde die Logik im Controller verbleiben und die E-Mail nicht korrekt versendet werden, gäbe es nie einen erneuten Versuch. Je nach Messenger-Konfiguration können die Anzahl der Wiederholungsversuche und die Intervalle zwischen ihnen verwaltet werden.