1111use Sentry \State \Scope ;
1212use Symfony \Component \Messenger \Event \WorkerMessageFailedEvent ;
1313use Symfony \Component \Messenger \Event \WorkerMessageHandledEvent ;
14+ use Symfony \Component \Messenger \Event \WorkerMessageReceivedEvent ;
1415use Symfony \Component \Messenger \Exception \DelayedMessageHandlingException ;
1516use Symfony \Component \Messenger \Exception \HandlerFailedException ;
1617use Symfony \Component \Messenger \Exception \WrappedExceptionsInterface ;
@@ -30,15 +31,25 @@ final class MessengerListener
3031 private $ captureSoftFails ;
3132
3233 /**
33- * @param HubInterface $hub The current hub
34- * @param bool $captureSoftFails Whether to capture errors thrown
35- * while processing a message that
36- * will be retried
34+ * @var bool When this is enabled, a new scope is pushed on the stack when a message
35+ * is received and will pop it again after the message was finished (either success or fail).
36+ * This allows us to have breadcrumbs only for one message and no breadcrumb is leaked into
37+ * future messages.
3738 */
38- public function __construct (HubInterface $ hub , bool $ captureSoftFails = true )
39+ private $ isolateBreadcrumbsByMessage ;
40+
41+ /**
42+ * @param HubInterface $hub The current hub
43+ * @param bool $captureSoftFails Whether to capture errors thrown
44+ * while processing a message that
45+ * will be retried
46+ * @param bool $isolateBreadcrumbsByMessage Whether messages should have isolated breadcrumbs
47+ */
48+ public function __construct (HubInterface $ hub , bool $ captureSoftFails = true , bool $ isolateBreadcrumbsByMessage = false )
3949 {
4050 $ this ->hub = $ hub ;
4151 $ this ->captureSoftFails = $ captureSoftFails ;
52+ $ this ->isolateBreadcrumbsByMessage = $ isolateBreadcrumbsByMessage ;
4253 }
4354
4455 /**
@@ -48,28 +59,36 @@ public function __construct(HubInterface $hub, bool $captureSoftFails = true)
4859 */
4960 public function handleWorkerMessageFailedEvent (WorkerMessageFailedEvent $ event ): void
5061 {
51- if (!$ this ->captureSoftFails && $ event ->willRetry ()) {
52- return ;
53- }
62+ try {
63+ if (!$ this ->captureSoftFails && $ event ->willRetry ()) {
64+ return ;
65+ }
5466
55- $ this ->hub ->withScope (function (Scope $ scope ) use ($ event ): void {
56- $ envelope = $ event ->getEnvelope ();
57- $ exception = $ event ->getThrowable ();
67+ $ this ->hub ->withScope (function (Scope $ scope ) use ($ event ): void {
68+ $ envelope = $ event ->getEnvelope ();
69+ $ exception = $ event ->getThrowable ();
5870
59- $ scope ->setTag ('messenger.receiver_name ' , $ event ->getReceiverName ());
60- $ scope ->setTag ('messenger.message_class ' , \get_class ($ envelope ->getMessage ()));
71+ $ scope ->setTag ('messenger.receiver_name ' , $ event ->getReceiverName ());
72+ $ scope ->setTag ('messenger.message_class ' , \get_class ($ envelope ->getMessage ()));
6173
62- /** @var BusNameStamp|null $messageBusStamp */
63- $ messageBusStamp = $ envelope ->last (BusNameStamp::class);
74+ /** @var BusNameStamp|null $messageBusStamp */
75+ $ messageBusStamp = $ envelope ->last (BusNameStamp::class);
6476
65- if (null !== $ messageBusStamp ) {
66- $ scope ->setTag ('messenger.message_bus ' , $ messageBusStamp ->getBusName ());
67- }
77+ if (null !== $ messageBusStamp ) {
78+ $ scope ->setTag ('messenger.message_bus ' , $ messageBusStamp ->getBusName ());
79+ }
6880
69- $ this ->captureException ($ exception , $ event ->willRetry ());
70- });
81+ $ this ->captureException ($ exception , $ event ->willRetry ());
82+ });
7183
72- $ this ->flushClient ();
84+ $ this ->flushClient ();
85+ } finally {
86+ // We always want to pop the scope at the end of this method to add the breadcrumbs
87+ // to any potential event that is produced.
88+ if ($ this ->isolateBreadcrumbsByMessage ) {
89+ $ this ->hub ->popScope ();
90+ }
91+ }
7392 }
7493
7594 /**
@@ -82,6 +101,24 @@ public function handleWorkerMessageHandledEvent(WorkerMessageHandledEvent $event
82101 // Flush normally happens at shutdown... which only happens in the worker if it is run with a lifecycle limit
83102 // such as --time=X or --limit=Y. Flush immediately in a background worker.
84103 $ this ->flushClient ();
104+ if ($ this ->isolateBreadcrumbsByMessage ) {
105+ $ this ->hub ->popScope ();
106+ }
107+ }
108+
109+ /**
110+ * Method that will push a new scope on the hub to create message local breadcrumbs that will not
111+ * "leak" into future messages.
112+ *
113+ * @param WorkerMessageReceivedEvent $event
114+ *
115+ * @return void
116+ */
117+ public function handleWorkerMessageReceivedEvent (WorkerMessageReceivedEvent $ event ): void
118+ {
119+ if ($ this ->isolateBreadcrumbsByMessage ) {
120+ $ this ->hub ->pushScope ();
121+ }
85122 }
86123
87124 /**
0 commit comments