Класс DispatchAfterCurrentBusStamp
Класс DispatchAfterCurrentBusStamp является штампом (stamp) и вешается на конверт сообщения через метод with. Когда сообщение с этим штампом передаётся в шину во время обработки другого сообщения, оно не отправляется немедленно, а откладывается до момента, когда текущее сообщение будет полностью обработано. Это защищает от рекурсивной и непредсказуемой отправки сообщений внутри обработчика. Параметров у класса нет.
Синтаксис
use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp;
$envelope = $envelope->with(new DispatchAfterCurrentBusStamp());
Пример
Давайте создадим два сообщения и обработчик, который во время своей работы отправляет второе сообщение с штампом DispatchAfterCurrentBusStamp:
<?php
namespace App\Message;
class FirstMessage
{
public function __construct(
public string $text = 'abcde'
) {
}
}
?>
<?php
namespace App\Message;
class SecondMessage
{
public function __construct(
public string $text = 'hello'
) {
}
}
?>
<?php
namespace App\MessageHandler;
use App\Message\FirstMessage;
use App\Message\SecondMessage;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
class FirstMessageHandler
{
public function __construct(
private MessageBusInterface $bus
) {
}
public function __invoke(FirstMessage $message): void
{
echo "first: " . $message->text . "\n";
$envelope = new Envelope(new SecondMessage('hello'));
$envelope = $envelope->with(new DispatchAfterCurrentBusStamp());
$this->bus->dispatch($envelope);
echo "first done\n";
}
}
?>
<?php
namespace App\MessageHandler;
use App\Message\SecondMessage;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
class SecondMessageHandler
{
public function __invoke(SecondMessage $message): void
{
echo "second: " . $message->text . "\n";
}
}
?>
Теперь отправим первое сообщение в шину:
<?php
namespace App\Controller;
use App\Message\FirstMessage;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;
class ArticleController extends AbstractController
{
#[Route('/', name: 'article_index')]
public function index(MessageBusInterface $bus): Response
{
$bus->dispatch(new FirstMessage('abcde'));
return new Response('ok');
}
}
?>
Результат выполнения кода:
first: abcde
first done
second: hello
Обратите внимание: второе сообщение обрабатывается только после того, как первый обработчик завершил работу, несмотря на то, что dispatch был вызван внутри него.
Пример
Давайте сравним поведение с штампом и без него. Уберём DispatchAfterCurrentBusStamp из обработчика:
<?php
namespace App\MessageHandler;
use App\Message\FirstMessage;
use App\Message\SecondMessage;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
class FirstMessageHandler
{
public function __construct(
private MessageBusInterface $bus
) {
}
public function __invoke(FirstMessage $message): void
{
echo "first: " . $message->text . "\n";
$this->bus->dispatch(new SecondMessage('hello'));
echo "first done\n";
}
}
?>
Результат выполнения кода:
first: abcde
second: hello
first done
Без штампа второе сообщение обрабатывается синхронно прямо внутри первого обработчика, что может привести к неожиданным побочным эффектам.
Смотрите также
-
класс
Envelope,
который оборачивает сообщение и его штампы -
метод
with,
который добавляет штамп к конверту -
метод
dispatch,
который отправляет сообщение в шину -
класс
MessageBus,
который реализует шину сообщений