feature #30676 Avoid dispatching SendMessageToTransportsEvent on redeliver (weaverryan)

This PR was merged into the 4.3-dev branch.

Discussion
----------

Avoid dispatching SendMessageToTransportsEvent on redeliver

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | yes - I think so
| New feature?  | no
| BC breaks?    | no (feature only on master)
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | none
| License       | MIT
| Doc PR        | a lot, soon :)

This purpose of this event is to be a hook when a message is sent to a transport.
If that message is redelivered later, that's not the purpose of this hook (there
are Worker events for that) and could cause problems if the user unknowingly
tries to modify the Envelope in some way, not thinking about how this might
be a redelivery message.

Commits
-------

3ac6bf9f24 Avoid dispatching SendMessageToTransportsEvent on redeliver
This commit is contained in:
Fabien Potencier 2019-03-26 07:14:35 +01:00
commit 0034a0f420
3 changed files with 40 additions and 10 deletions

View File

@ -20,6 +20,8 @@ use Symfony\Component\Messenger\Envelope;
* The event is *only* dispatched if the message will actually
* be sent to at least one transport. If the message is sent
* to multiple transports, the message is dispatched only one time.
* This message is only dispatched the first time a message
* is sent to a transport, not also if it is retried.
*
* @author Ryan Weaver <ryan@symfonycasts.com>
*/

View File

@ -62,20 +62,21 @@ class SendMessageMiddleware implements MiddlewareInterface
/** @var RedeliveryStamp|null $redeliveryStamp */
$redeliveryStamp = $envelope->last(RedeliveryStamp::class);
$senders = \iterator_to_array($this->sendersLocator->getSenders($envelope, $handle));
if (null !== $this->eventDispatcher && \count($senders) > 0) {
$event = new SendMessageToTransportsEvent($envelope);
$this->eventDispatcher->dispatch($event);
$envelope = $event->getEnvelope();
}
foreach ($senders as $alias => $sender) {
// dispatch event unless this is a redelivery
$shouldDispatchEvent = null === $redeliveryStamp;
foreach ($this->sendersLocator->getSenders($envelope, $handle) as $alias => $sender) {
// on redelivery, only deliver to the given sender
if (null !== $redeliveryStamp && !$redeliveryStamp->shouldRedeliverToSender(\get_class($sender), $alias)) {
continue;
}
if (null !== $this->eventDispatcher && $shouldDispatchEvent) {
$event = new SendMessageToTransportsEvent($envelope);
$this->eventDispatcher->dispatch($event);
$envelope = $event->getEnvelope();
$shouldDispatchEvent = false;
}
$this->logger->info('Sending message "{class}" with "{sender}"', $context + ['sender' => \get_class($sender)]);
$envelope = $sender->send($envelope->with(new SentStamp(\get_class($sender), \is_string($alias) ? $alias : null)));
}

View File

@ -205,7 +205,7 @@ class SendMessageMiddlewareTest extends MiddlewareTestCase
$this->assertNull($envelope->last(SentStamp::class), 'it does not add sent stamp for received messages');
}
public function testItDispatchesTheEventOnceTime()
public function testItDispatchesTheEventOneTime()
{
$envelope = new Envelope(new DummyMessage('original envelope'));
@ -224,4 +224,31 @@ class SendMessageMiddlewareTest extends MiddlewareTestCase
$middleware->handle($envelope, $this->getStackMock(false));
}
public function testItDoesNotDispatchWithNoSenders()
{
$envelope = new Envelope(new DummyMessage('original envelope'));
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$dispatcher->expects($this->never())->method('dispatch');
$middleware = new SendMessageMiddleware(new SendersLocator([]), $dispatcher);
$middleware->handle($envelope, $this->getStackMock());
}
public function testItDoesNotDispatchOnRetry()
{
$envelope = new Envelope(new DummyMessage('original envelope'));
$envelope = $envelope->with(new RedeliveryStamp(3, 'foo_sender'));
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$dispatcher->expects($this->never())->method('dispatch');
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$middleware = new SendMessageMiddleware(new SendersLocator([DummyMessage::class => [$sender]]), $dispatcher);
$middleware->handle($envelope, $this->getStackMock(false));
}
}