Die Messenger-Komponente von Symfony ermöglicht es Entwicklern, Nachrichten zwischen verschiedenen Teilen einer Anwendung zu senden und zu empfangen, sowohl synchron als auch asynchron. Sie unterstützt die Verwendung von Nachrichtenwarteschlangen und bietet Integrationen mit Message Brokern wie RabbitMQ und Redis.
In diesem Artikel werden wir die folgenden Themen ausführlich behandeln:
- Einführung in die Messenger-Komponente
- Senden und Verarbeiten von Nachrichten
- Asynchrone Verarbeitung und Nachrichtenwarteschlangen
- Integration mit Message Brokern (RabbitMQ, Redis)
1. Einführung in die Messenger-Komponente
1.1 Was ist die Messenger-Komponente?
Die Messenger-Komponente ist ein Werkzeug zur Implementierung von Nachrichtenverarbeitung in Symfony-Anwendungen. Sie ermöglicht das Senden von Nachrichten (oder Befehlen) und die Verarbeitung dieser Nachrichten durch Handler. Dies fördert die Trennung von Anliegen und erleichtert die asynchrone Verarbeitung von Aufgaben.
1.2 Vorteile der Verwendung der Messenger-Komponente
- Lose Kopplung: Komponenten kommunizieren über Nachrichten statt direkte Aufrufe.
- Asynchrone Verarbeitung: Aufgaben können asynchron in Hintergrundprozessen ausgeführt werden.
- Skalierbarkeit: Durch die Verwendung von Warteschlangen können Anwendungen besser skaliert werden.
- Fehlerbehandlung: Verbesserte Kontrolle über die Fehlerbehandlung und Wiederholungsmechanismen.
1.3 Installation der Messenger-Komponente
Falls nicht bereits installiert, können Sie die Messenger-Komponente mit Composer hinzufügen:
composer require symfony/messenger
2. Senden und Verarbeiten von Nachrichten
2.1 Grundlagen des Nachrichtenversands
Eine Nachricht ist ein einfaches PHP-Objekt, das Daten enthält. Ein Handler ist eine Klasse, die die Nachricht empfängt und verarbeitet.
2.2 Erstellen einer Nachricht
Beispiel:
Angenommen, wir möchten eine E-Mail versenden, wenn ein Benutzer sich registriert.
// src/Message/SendWelcomeEmail.php
namespace App\Message;
class SendWelcomeEmail
{
private int $userId;
public function __construct(int $userId)
{
$this->userId = $userId;
}
public function getUserId(): int
{
return $this->userId;
}
}
2.3 Erstellen eines Handlers
Der Handler verarbeitet die Nachricht und führt die gewünschte Aktion aus.
// src/MessageHandler/SendWelcomeEmailHandler.php
namespace App\MessageHandler;
use App\Message\SendWelcomeEmail;
use App\Repository\UserRepository;
use App\Service\MailerService;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class SendWelcomeEmailHandler implements MessageHandlerInterface
{
private UserRepository $userRepository;
private MailerService $mailer;
public function __construct(UserRepository $userRepository, MailerService $mailer)
{
$this->userRepository = $userRepository;
$this->mailer = $mailer;
}
public function __invoke(SendWelcomeEmail $message)
{
$user = $this->userRepository->find($message->getUserId());
if (!$user) {
// Benutzer nicht gefunden, Fehlerbehandlung
return;
}
// E-Mail senden
$this->mailer->sendWelcomeEmail($user);
}
}
2.4 Senden der Nachricht
In Ihrem Controller oder Service können Sie die Nachricht senden.
// src/Controller/RegistrationController.php
namespace App\Controller;
use App\Entity\User;
use App\Form\RegistrationFormType;
use App\Message\SendWelcomeEmail;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
class RegistrationController extends AbstractController
{
#[Route('/register', name: 'user_register')]
public function register(
Request $request,
EntityManagerInterface $entityManager,
MessageBusInterface $messageBus
) {
$user = new User();
$form = $this->createForm(RegistrationFormType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Benutzer speichern
$entityManager->persist($user);
$entityManager->flush();
// Nachricht senden
$messageBus->dispatch(new SendWelcomeEmail($user->getId()));
// Weiterleitung oder Antwort
return $this->redirectToRoute('homepage');
}
return $this->render('registration/register.html.twig', [
'registrationForm' => $form->createView(),
]);
}
}
2.5 Wichtige Komponenten
- MessageBusInterface: Schnittstelle zum Senden von Nachrichten.
- Message: Die Nachricht, die gesendet wird.
- MessageHandlerInterface: Schnittstelle für den Handler, der die Nachricht verarbeitet.
3. Asynchrone Verarbeitung und Nachrichtenwarteschlangen
3.1 Warum asynchron verarbeiten?
Asynchrone Verarbeitung ermöglicht es, langwierige oder ressourcenintensive Aufgaben im Hintergrund auszuführen, ohne die Benutzererfahrung zu beeinträchtigen.
3.2 Konfiguration der asynchronen Verarbeitung
Schritt 1: Transport konfigurieren
In der Konfigurationsdatei config/packages/messenger.yaml
können Sie den Transport konfigurieren.
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: 'doctrine://default' # Verwenden der Datenbank als Warteschlange
default_bus: messenger.bus.default
buses:
messenger.bus.default: ~
routing:
'App\Message\SendWelcomeEmail': async
Erklärung:
- transports.async: Definiert einen Transport namens
async
mit der Datenbank als Backend. - routing: Weist Nachrichten einem Transport zu. In diesem Fall wird
SendWelcomeEmail
an denasync
-Transport gesendet.
Schritt 2: Nachrichten asynchron senden
Der Code zum Senden der Nachricht bleibt unverändert. Durch die Konfiguration wird die Nachricht nun in die Warteschlange gelegt.
Schritt 3: Worker starten
Um die Nachrichten in der Warteschlange zu verarbeiten, müssen Sie einen Worker starten.
php bin/console messenger:consume async
Der Worker liest die Nachrichten aus der Warteschlange und führt die Handler aus.
3.3 Verwendung von Serialisierern
Da Nachrichten über einen Transport gesendet werden, müssen sie serialisiert werden. Symfony verwendet den Serializer automatisch. Stellen Sie sicher, dass Ihre Nachrichten serialisierbar sind.
3.4 Wiederholungsmechanismen und Fehlerbehandlung
Die Messenger-Komponente bietet Mechanismen, um fehlgeschlagene Nachrichten erneut zu versuchen oder in eine Fehlerwarteschlange zu verschieben.
Konfiguration von Wiederholungen:
# config/packages/messenger.yaml
framework:
messenger:
failure_transport: failed
transports:
async: 'doctrine://default'
failed: 'doctrine://default'
# ...
Verarbeiten fehlgeschlagener Nachrichten:
Sie können fehlgeschlagene Nachrichten mit folgendem Befehl erneut versuchen:
php bin/console messenger:retry failed
Oder die fehlgeschlagenen Nachrichten anzeigen:
php bin/console messenger:failed:show
4. Integration mit Message Brokern (RabbitMQ, Redis)
4.1 Warum Message Broker verwenden?
Message Broker wie RabbitMQ oder Redis bieten robuste und skalierbare Lösungen für die Nachrichtenverarbeitung. Sie ermöglichen eine bessere Performance und Zuverlässigkeit als die Verwendung der Datenbank als Warteschlange.
4.2 Integration mit RabbitMQ
Schritt 1: Installation von RabbitMQ
Installieren Sie RabbitMQ auf Ihrem System oder verwenden Sie einen gehosteten Dienst.
Schritt 2: Installation des AMQP-Pakets
Symfony benötigt das AMQP-Paket, um mit RabbitMQ zu kommunizieren.
composer require symfony/amqp-messenger
Schritt 3: Konfiguration des Transports
Passen Sie die messenger.yaml
an:
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: 'amqp://guest:guest@localhost:5672/%2f/messages'
# ...
Erklärung:
- amqp://guest:guest@localhost:5672/%2f/messages: AMQP-Verbindungszeichenfolge zu RabbitMQ.
Schritt 4: RabbitMQ Exchange und Queue konfigurieren
Die Messenger-Komponente erstellt automatisch die erforderlichen Exchanges und Queues. Sie können jedoch auch benutzerdefinierte Einstellungen vornehmen.
Schritt 5: Worker starten
php bin/console messenger:consume async
4.3 Integration mit Redis
Schritt 1: Installation von Redis
Installieren Sie Redis auf Ihrem System oder verwenden Sie einen gehosteten Dienst.
Schritt 2: Installation des Redis-Pakets
composer require symfony/redis-messenger
Schritt 3: Konfiguration des Transports
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: 'redis://localhost:6379/messages'
# ...
Erklärung:
- redis://localhost:6379/messages: Verbindungszeichenfolge zu Redis.
4.4 Verwendung von Middleware
Middleware ermöglicht es, zusätzliche Verarbeitungsschritte vor oder nach dem Nachrichtentransport hinzuzufügen.
Beispiel: Logging Middleware
// src/Middleware/LoggingMiddleware.php
namespace App\Middleware;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
class LoggingMiddleware implements MiddlewareInterface
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function handle(Envelope $envelope, StackInterface $stack): Envelope
{
$this->logger->info('Verarbeitung der Nachricht: ' . get_class($envelope->getMessage()));
return $stack->next()->handle($envelope, $stack);
}
}
Registrieren der Middleware
# config/packages/messenger.yaml
framework:
messenger:
buses:
messenger.bus.default:
middleware:
- 'App\Middleware\LoggingMiddleware'
- 'dispatch_after_current_bus'
4.5 Mehrere Busse verwenden
Sie können mehrere Message Busse definieren, um verschiedene Arten von Nachrichten zu trennen.
Konfiguration:
# config/packages/messenger.yaml
framework:
messenger:
default_bus: command.bus
buses:
command.bus:
default_middleware: true
event.bus:
default_middleware: true
Verwendung in Ihrem Code:
// Senden einer Nachricht über den command.bus
$commandBus->dispatch(new SomeCommand());
// Senden einer Nachricht über den event.bus
$eventBus->dispatch(new SomeEvent());
Zusammenfassung
- Messenger-Komponente: Ermöglicht das Senden und Verarbeiten von Nachrichten in Symfony-Anwendungen.
- Senden und Verarbeiten von Nachrichten: Nachrichten werden gesendet und von Handlern verarbeitet, was eine lose Kopplung ermöglicht.
- Asynchrone Verarbeitung: Durch die Verwendung von Transporten und Workern können Nachrichten asynchron verarbeitet werden.
- Integration mit Message Brokern: Durch die Verwendung von RabbitMQ oder Redis können Sie skalierbare und robuste Nachrichtenverarbeitung implementieren.
- Erweiterbarkeit: Middleware und mehrere Busse ermöglichen die Anpassung und Erweiterung der Nachrichtenverarbeitung.
Weiterführende Ressourcen
Messenger: Sync & Queued Message Handling