Pimcore Blog

Wie benutzt man Symfony Messenger mit Pimcore? | pimcore.com

Geschrieben von Mateusz Soroka | 23.11.2022 05:00:00

Verschwenden Sie nicht Ihre Zeit mit Warten - lassen Sie Symfony Messenger die Arbeit im Hintergrund in Ihrer Pimcore-Anwendung erledigen.

Was ist Symfony Messenger?

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.

Anwendungsfall im wirklichen Leben

Nehmen wir an, es gibt ein Gewinnspielformular auf Ihrer Website, sogar ein sehr einfaches mit drei Feldern:

  • Vorname
  • E-Mail
  • Nachricht

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.

Diese Datei enthält bidirektionalen Unicode-Text, der möglicherweise anders interpretiert oder kompiliert wird als unten angegeben. Öffnen Sie die Datei zur Überprüfung in einem Editor, der versteckte Unicode-Zeichen sichtbar macht. Erfahren Sie mehr über bidirektionale Unicode-Zeichen
<?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?

Wo liegt das Problem?

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.

Die Magie der Warteschlangen

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:

  • CompetitionApplicationMessage, die Daten speichert, in diesem FallCompetitionApplication
  • CompetitionApplicationMessageHandler, der in diesem Fall für die Speicherung des Objekts und den Versand der E-Mail zuständig ist.

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.

Asynchronität ist der Schlüssel

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.

Ergebnisse

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.

Ressourcen