diff --git a/src/DispatchFailed.php b/src/DispatchFailed.php new file mode 100644 index 0000000..af45e3a --- /dev/null +++ b/src/DispatchFailed.php @@ -0,0 +1,53 @@ +exception; + } + + /** + * @return callable + */ + public function getListener(): callable + { + return is_callable($this->listener) ? $this->listener : fn() => null; + } + + /** + * @return object + */ + public function getEvent(): object + { + return $this->event; + } +} diff --git a/src/EventEnvelope.php b/src/EventEnvelope.php new file mode 100644 index 0000000..f48eab9 --- /dev/null +++ b/src/EventEnvelope.php @@ -0,0 +1,46 @@ + $context Immutable metadata associated with the event. + */ + public function __construct( + private readonly object $event, + private readonly array $context = [] + ) { + } + + /** + * Returns the underlying event. + * + * @return object + */ + public function getEvent(): object + { + return $this->event; + } + + /** + * Returns the context map. + * + * @return array + */ + public function getContext(): array + { + return $this->context; + } +} diff --git a/src/ResiliencyMode.php b/src/ResiliencyMode.php new file mode 100644 index 0000000..4a54fd7 --- /dev/null +++ b/src/ResiliencyMode.php @@ -0,0 +1,23 @@ +setResiliencyMode(ResiliencyMode::FAIL_FAST); + + $provider->addListener('stdClass', function() { + throw new \RuntimeException('Test Error'); + }); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Test Error'); + + $dispatcher->dispatch(new \stdClass()); + } + + public function test_it_continues_and_reports_in_continue_mode(): void + { + $provider = new ListenerProvider(); + $dispatcher = new EventDispatcher($provider); + $dispatcher->setResiliencyMode(ResiliencyMode::CONTINUE); + + $failedCount = 0; + $listenersRun = 0; + + // Listener that fails + $provider->addListener('stdClass', function() { + throw new \RuntimeException('Test Error'); + }); + + // Next listener that should still run + $provider->addListener('stdClass', function() use (&$listenersRun) { + $listenersRun++; + }); + + // Error reporter listener + $provider->addListener(DispatchFailed::class, function(DispatchFailed $event) use (&$failedCount) { + $failedCount++; + $this->assertEquals('Test Error', $event->getException()->getMessage()); + }); + + $dispatcher->dispatch(new \stdClass()); + + $this->assertEquals(1, $listenersRun); + $this->assertEquals(1, $failedCount); + } + + public function test_event_envelope_carries_context(): void + { + $event = new \stdClass(); + $context = ['request_id' => '123']; + $envelope = new EventEnvelope($event, $context); + + $this->assertSame($event, $envelope->getEvent()); + $this->assertEquals($context, $envelope->getContext()); + } +}