10000 [Scheduler] Add failureEvent · symfony/symfony@891a404 · GitHub
[go: up one dir, main page]

Skip to content

Commit 891a404

Browse files
committed
[Scheduler] Add failureEvent
1 parent abe5555 commit 891a404

File tree

6 files changed

+122
-12
lines changed

6 files changed

+122
-12
lines changed

src/Symfony/Component/Scheduler/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ CHANGELOG
1515
* Add `MessageProviderInterface` to trigger unique messages at runtime
1616
* Add `PreRunEvent` and `PostRunEvent` events
1717
* Add `DispatchSchedulerEventListener`
18+
* Add `FailureEvent` event
1819

1920
6.3
2021
---
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Scheduler\Event;
13+
14+
use Symfony\Component\Scheduler\Generator\MessageContext;
15+
use Symfony\Component\Scheduler\ScheduleProviderInterface;
16+
17+
class FailureEvent
18+
{
19+
private bool $shouldIgnore = false;
20+
21+
public function __construct(
22+
private readonly ScheduleProviderInterface $schedule,
23+
private readonly MessageContext $messageContext,
24+
private readonly object $message,
25+
private readonly \Throwable $error,
26+
) {
27+
}
28+
29+
public function getMessageContext(): MessageContext
30+
{
31+
return $this->messageContext;
32+
}
33+
34+
public function getSchedule(): ScheduleProviderInterface
35+
{
36+
return $this->schedule;
37+
}
38+
39+
public function getMessage(): object
40+
{
41+
return $this->message;
42+
}
43+
44+
public function getError(): \Throwable
45+
{
46+
return $this->error;
47+
}
48+
49+
public function shouldIgnore(bool $shouldIgnore = null): bool
50+
{
51+
if (null !== $shouldIgnore) {
52+
$this->shouldIgnore = $shouldIgnore;
53+
}
54+
55+
return $this->shouldIgnore;
56+
}
57+
}

src/Symfony/Component/Scheduler/EventListener/DispatchSchedulerEventListener.php

+31-9
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414
use Psr\Container\ContainerInterface;
1515
use Psr\EventDispatcher\EventDispatcherInterface;
1616
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17+
use Symfony\Component\Messenger\Envelope;
18+
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
1719
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
1820
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
21+
use Symfony\Component\Messenger\Stamp\StampInterface;
22+
use Symfony\Component\Scheduler\Event\FailureEvent;
1923
use Symfony\Component\Scheduler\Event\PostRunEvent;
2024
use Symfony\Component\Scheduler\Event\PreRunEvent;
2125
use Symfony\Component\Scheduler\Messenger\ScheduledStamp;
@@ -31,11 +35,8 @@ public function __construct(
3135
public function onMessageHandled(WorkerMessageHandledEvent $event): void
3236
{
3337
$envelope = $event->getEnvelope();
34-
if (!$scheduledStamp = $envelope->last(ScheduledStamp::class)) {
35-
return;
36-
}
3738

38-
if (!$this->scheduleProviderLocator->has($scheduledStamp->messageContext->name)) {
39+
if (!$scheduledStamp = $this->getScheduledStamp($envelope)) {
3940
return;
4041
}
4142

@@ -46,11 +47,7 @@ public function onMessageReceived(WorkerMessageReceivedEvent $event): void
4647
{
4748
$envelope = $event->getEnvelope();
4849

49-
if (!$scheduledStamp = $envelope->last(ScheduledStamp::class)) {
50-
return;
51-
}
52-
53-
if (!$this->scheduleProviderLocator->has($scheduledStamp->messageContext->name)) {
50+
if (!$scheduledStamp = $this->getScheduledStamp($envelope)) {
5451
return;
5552
}
5653

@@ -63,11 +60,36 @@ public function onMessageReceived(WorkerMessageReceivedEvent $event): void
6360
}
6461
}
6562

63+
public function onMessageFailed(WorkerMessageFailedEvent $event): void
64+
{
65+
$envelope = $event->getEnvelope();
66+
67+
if (!$scheduledStamp = $this->getScheduledStamp($envelope)) {
68+
return;
69+
}
70+
71+
$this->eventDispatcher->dispatch(new FailureEvent($this->scheduleProviderLocator->get($scheduledStamp->messageContext->name), $scheduledStamp->messageContext, $envelope->getMessage(), $event->getThrowable()));
72+
}
73+
74+
private function getScheduledStamp(Envelope $envelope): ?StampInterface
75+
{
76+
if (!$scheduledStamp = $envelope->last(ScheduledStamp::class)) {
77+
return null;
78+
}
79+
80+
if (!$this->scheduleProviderLocator->has($scheduledStamp->messageContext->name)) {
81+
return null;
82+
}
83+
84+
return $scheduledStamp;
85+
}
86+
6687
public static function getSubscribedEvents(): array
6788
{
6889
return [
6990
WorkerMessageReceivedEvent::class => ['onMessageReceived'],
7091
WorkerMessageHandledEvent::class => ['onMessageHandled'],
92+
WorkerMessageFailedEvent::class => ['onMessageFailed'],
7193
];
7294
}
7395
}

src/Symfony/Component/Scheduler/Schedule.php

+8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1515
use Symfony\Component\Lock\LockInterface;
16+
use Symfony\Component\Scheduler\Event\FailureEvent;
1617
use Symfony\Component\Scheduler\Event\PostRunEvent;
1718
use Symfony\Component\Scheduler\Event\PreRunEvent;
1819
use Symfony\Component\Scheduler\Exception\LogicException;
@@ -152,6 +153,13 @@ public function after(callable $listener, int $priority = 0): static
152153
return $this;
153154
}
154155

156+
public function onFailure(callable $listener, int $priority = 0): static
157+
{
158+
$this->dispatcher->addListener(FailureEvent::class, $listener, $priority);
159+
160+
return $this;
161+
}
162+
155163
public function shouldRestart(): bool
156164
{
157165
return $this->shouldRestart;

src/Symfony/Component/Scheduler/Scheduler.php

+13-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Psr\EventDispatcher\EventDispatcherInterface;
1515
use Symfony\Component\Clock\Clock;
1616
use Symfony\Component\Clock\ClockInterface;
17+
use Symfony\Component\Scheduler\Event\FailureEvent;
1718
use Symfony\Component\Scheduler\Event\PostRunEvent;
1819
use Symfony\Component\Scheduler\Event\PreRunEvent;
1920
use Symfony\Component\Scheduler\Generator\MessageGenerator;
@@ -81,10 +82,19 @@ public function run(array $options = []): void
8182
continue;
8283
}
8384

84-
$this->handlers[$message::class]($message);
85-
$ran = true;
85+
try {
86+
$this->handlers[$message::class]($message);
87+
$ran = true;
8688

87-
$this->dispatcher->dispatch(new PostRunEvent($generator->getSchedule(), $context, $message));
89+
$this->dispatcher->dispatch(new PostRunEvent($generator->getSchedule(), $context, $message));
90+
} catch (\Throwable $error) {
91+
$failureEvent = new FailureEvent($generator->getSchedule(), $context, $message, $error);
92+
$this->dispatcher->dispatch($failureEvent);
93+
94+
if (!$failureEvent->shouldIgnore()) {
95+
throw $error;
96+
}
97+
}
8898
}
8999
}
90100

src/Symfony/Component/Scheduler/Tests/EventListener/DispatchSchedulerEventListenerTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
use Psr\Container\ContainerInterface;
1616
use Symfony\Component\EventDispatcher\EventDispatcher;
1717
use Symfony\Component\Messenger\Envelope;
18+
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
1819
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
1920
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
21+
use Symfony\Component\Scheduler\Event\FailureEvent;
2022
use Symfony\Component\Scheduler\Event\PostRunEvent;
2123
use Symfony\Component\Scheduler\Event\PreRunEvent;
2224
use Symfony\Component\Scheduler\EventListener\DispatchSchedulerEventListener;
@@ -45,15 +47,19 @@ public function testDispatchSchedulerEvents()
4547
$listener = new DispatchSchedulerEventListener($scheduleProviderLocator, $eventDispatcher = new EventDispatcher());
4648
$workerReceivedEvent = new WorkerMessageReceivedEvent($envelope, 'default');
4749
$workerHandledEvent = new WorkerMessageHandledEvent($envelope, 'default');
50+
$workerFailedEvent = new WorkerMessageFailedEvent($envelope, 'default', new \Exception());
4851
$secondListener = new TestEventListener();
4952

5053
$eventDispatcher->addListener(PreRunEvent::class, [$secondListener, 'preRun']);
5154
$eventDispatcher->addListener(PostRunEvent::class, [$secondListener, 'postRun']);
55+
$eventDispatcher->addListener(FailureEvent::class, [$secondListener, 'onFailure']);
5256
$listener->onMessageReceived($workerReceivedEvent);
5357
$listener->onMessageHandled($workerHandledEvent);
58+
$listener->onMessageFailed($workerFailedEvent);
5459

5560
$this->assertTrue($secondListener->preInvoked);
5661
$this->assertTrue($secondListener->postInvoked);
62+
$this->assertTrue($secondListener->failureInvoked);
5763
}
5864
}
5965

@@ -62,6 +68,7 @@ class TestEventListener
6268
public string $name;
6369
public bool $preInvoked = false;
6470
public bool $postInvoked = false;
71+
public bool $failureInvoked = false;
6572

6673
/* Listener methods */
6774

@@ -74,4 +81,9 @@ public function postRun($e)
7481
{
7582
$this->postInvoked = true;
7683
}
84+
85+
public function onFailure($e)
86+
{
87+
$this->failureInvoked = true;
88+
}
7789
}

0 commit comments

Comments
 (0)
0