) - a key/value pair of headers
+ *
+ * @throws MessageDecodingFailedException
*/
public function decode(array $encodedEnvelope): Envelope;
diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php
index ae903217acebb..19c5a4b0fafea 100644
--- a/src/Symfony/Component/Messenger/Worker.php
+++ b/src/Symfony/Component/Messenger/Worker.php
@@ -11,7 +11,19 @@
namespace Symfony\Component\Messenger;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
+use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
+use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
+use Symfony\Component\Messenger\Exception\LogicException;
+use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
+use Symfony\Component\Messenger\Retry\RetryStrategyInterface;
+use Symfony\Component\Messenger\Stamp\DelayStamp;
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
+use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
+use Symfony\Component\Messenger\Stamp\SentStamp;
use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface;
/**
@@ -25,11 +37,24 @@ class Worker
{
private $receiver;
private $bus;
+ private $receiverName;
+ private $retryStrategy;
+ private $eventDispatcher;
+ private $logger;
- public function __construct(ReceiverInterface $receiver, MessageBusInterface $bus)
+ public function __construct(ReceiverInterface $receiver, MessageBusInterface $bus, string $receiverName = null, RetryStrategyInterface $retryStrategy = null, EventDispatcherInterface $eventDispatcher = null, LoggerInterface $logger = null)
{
$this->receiver = $receiver;
$this->bus = $bus;
+ if (null === $receiverName) {
+ @trigger_error(sprintf('Instantiating the "%s" class without passing a third argument is deprecated since Symfony 4.3.', __CLASS__), E_USER_DEPRECATED);
+
+ $receiverName = 'unknown';
+ }
+ $this->receiverName = $receiverName;
+ $this->retryStrategy = $retryStrategy;
+ $this->eventDispatcher = $eventDispatcher;
+ $this->logger = $logger;
}
/**
@@ -45,10 +70,112 @@ public function run()
$this->receiver->receive(function (?Envelope $envelope) {
if (null === $envelope) {
+ if (\function_exists('pcntl_signal_dispatch')) {
+ pcntl_signal_dispatch();
+ }
+
return;
}
- $this->bus->dispatch($envelope->with(new ReceivedStamp()));
+ $this->dispatchEvent(new WorkerMessageReceivedEvent($envelope, $this->receiverName));
+
+ $message = $envelope->getMessage();
+ $context = [
+ 'message' => $message,
+ 'class' => \get_class($message),
+ ];
+
+ try {
+ $envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp()));
+ } catch (\Throwable $throwable) {
+ $shouldRetry = $this->shouldRetry($throwable, $envelope);
+
+ $this->dispatchEvent(new WorkerMessageFailedEvent($envelope, $this->receiverName, $throwable, $shouldRetry));
+
+ if ($shouldRetry) {
+ if (null === $this->retryStrategy) {
+ // not logically allowed, but check just in case
+ throw new LogicException('Retrying is not supported without a retry strategy.');
+ }
+
+ $retryCount = $this->getRetryCount($envelope) + 1;
+ if (null !== $this->logger) {
+ $this->logger->info('Retrying {class} - retry #{retryCount}.', $context + ['retryCount' => $retryCount, 'error' => $throwable]);
+ }
+
+ // add the delay and retry stamp info + remove ReceivedStamp
+ $retryEnvelope = $envelope->with(new DelayStamp($this->retryStrategy->getWaitingTime($envelope)))
+ ->with(new RedeliveryStamp($retryCount, $this->getSenderAlias($envelope)))
+ ->withoutAll(ReceivedStamp::class);
+
+ // re-send the message
+ $this->bus->dispatch($retryEnvelope);
+ // acknowledge the previous message has received
+ $this->receiver->ack($envelope);
+ } else {
+ if (null !== $this->logger) {
+ $this->logger->info('Rejecting {class} (removing from transport).', $context + ['error' => $throwable]);
+ }
+
+ $this->receiver->reject($envelope);
+ }
+
+ if (\function_exists('pcntl_signal_dispatch')) {
+ pcntl_signal_dispatch();
+ }
+
+ return;
+ }
+
+ $this->dispatchEvent(new WorkerMessageHandledEvent($envelope, $this->receiverName));
+
+ if (null !== $this->logger) {
+ $this->logger->info('{class} was handled successfully (acknowledging to transport).', $context);
+ }
+
+ $this->receiver->ack($envelope);
+
+ if (\function_exists('pcntl_signal_dispatch')) {
+ pcntl_signal_dispatch();
+ }
});
}
+
+ private function dispatchEvent(Event $event)
+ {
+ if (null === $this->eventDispatcher) {
+ return;
+ }
+
+ $this->eventDispatcher->dispatch($event);
+ }
+
+ private function shouldRetry(\Throwable $e, Envelope $envelope): bool
+ {
+ if ($e instanceof UnrecoverableMessageHandlingException) {
+ return false;
+ }
+
+ if (null === $this->retryStrategy) {
+ return false;
+ }
+
+ return $this->retryStrategy->isRetryable($envelope);
+ }
+
+ private function getRetryCount(Envelope $envelope): int
+ {
+ /** @var RedeliveryStamp|null $retryMessageStamp */
+ $retryMessageStamp = $envelope->last(RedeliveryStamp::class);
+
+ return $retryMessageStamp ? $retryMessageStamp->getRetryCount() : 0;
+ }
+
+ private function getSenderAlias(Envelope $envelope): ?string
+ {
+ /** @var SentStamp|null $sentStamp */
+ $sentStamp = $envelope->last(SentStamp::class);
+
+ return $sentStamp ? $sentStamp->getSenderAlias() : null;
+ }
}
diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json
index d0b6fe31f9888..d40963e2f6d18 100644
--- a/src/Symfony/Component/Messenger/composer.json
+++ b/src/Symfony/Component/Messenger/composer.json
@@ -22,6 +22,7 @@
"require-dev": {
"symfony/console": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4.19|^4.1.8",
+ "symfony/event-dispatcher": "~4.3",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/process": "~3.4|~4.0",
"symfony/property-access": "~3.4|~4.0",
@@ -30,6 +31,9 @@
"symfony/validator": "~3.4|~4.0",
"symfony/var-dumper": "~3.4|~4.0"
},
+ "conflict": {
+ "symfony/event-dispatcher": "<4.3"
+ },
"suggest": {
"enqueue/messenger-adapter": "For using the php-enqueue library as a transport."
},
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy