From 970d57724d5ad7d2518ced7de3f8626d98a11b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Frei?= Date: Tue, 5 Nov 2024 13:42:13 +0100 Subject: [PATCH 1/2] Ensure background listeners are called even if a foreground listener throws --- .../lib/events/DomainEventEmitter.spec.ts | 18 +++++++++ .../core/lib/events/DomainEventEmitter.ts | 38 ++++++++++--------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/packages/core/lib/events/DomainEventEmitter.spec.ts b/packages/core/lib/events/DomainEventEmitter.spec.ts index 9cfb7c0c..630f1d76 100644 --- a/packages/core/lib/events/DomainEventEmitter.spec.ts +++ b/packages/core/lib/events/DomainEventEmitter.spec.ts @@ -431,6 +431,24 @@ describe('AutopilotEventEmitter', () => { false, ) }) + + it('emits event to background even if foreground listener throws', async () => { + // Given + const fakeSyncListener = new FakeListener() + vi.spyOn(fakeSyncListener, 'handleEvent').mockRejectedValue(new Error('Test error')) + eventEmitter.on('entity.created', fakeSyncListener) + + const fakeAsyncListener = new FakeListener() + eventEmitter.on('entity.created', fakeAsyncListener, true) + + // When + const emittedEventPromise = eventEmitter.emit(TestEvents.created, createdEventPayload) + + // Then + expect(emittedEventPromise).rejects.toThrow('Test error') + await eventEmitter.handlerSpy.waitForMessage({ type: 'entity.created' }, 'consumed') + expect(fakeAsyncListener.receivedEvents).toHaveLength(1) + }) }) describe('dispose', () => { diff --git a/packages/core/lib/events/DomainEventEmitter.ts b/packages/core/lib/events/DomainEventEmitter.ts index f177c668..a5fd07f2 100644 --- a/packages/core/lib/events/DomainEventEmitter.ts +++ b/packages/core/lib/events/DomainEventEmitter.ts @@ -167,25 +167,27 @@ export class DomainEventEmitter const eventHandlers = this.eventHandlerMap.get(event.type) if (!eventHandlers) return - for (const handler of eventHandlers.foreground) { - await this.executeEventHandler(event, handler, false) + try { + for (const handler of eventHandlers.foreground) { + await this.executeEventHandler(event, handler, false) + } + } finally { + const bgPromise = Promise.all( + eventHandlers.background.map((handler) => this.executeEventHandler(event, handler, true)), + ).then(() => { + this.inProgressBackgroundHandlerByEventId.delete(event.id) + if (!this._handlerSpy) return + this._handlerSpy.addProcessedMessage( + { + // @ts-ignore + message: event, + processingResult: 'consumed', + }, + event.id, + ) + }) + this.inProgressBackgroundHandlerByEventId.set(event.id, bgPromise) } - - const bgPromise = Promise.all( - eventHandlers.background.map((handler) => this.executeEventHandler(event, handler, true)), - ).then(() => { - this.inProgressBackgroundHandlerByEventId.delete(event.id) - if (!this._handlerSpy) return - this._handlerSpy.addProcessedMessage( - { - // @ts-ignore - message: event, - processingResult: 'consumed', - }, - event.id, - ) - }) - this.inProgressBackgroundHandlerByEventId.set(event.id, bgPromise) } private async executeEventHandler( From 1b72de1afa91e6ca6092e1be3109a6142d3be3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Frei?= Date: Tue, 5 Nov 2024 13:43:53 +0100 Subject: [PATCH 2/2] Add note about build to README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index fd82b538..a7e47532 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ It consists of the following submodules: * `@message-queue-toolkit/sqs` - SQS (AWS Simple Queue Service) * `@message-queue-toolkit/sns` - SNS (AWS Simple Notification Service) +## Setup + +In order to be able to run tests, you first need to run `npm run build`. + ## Basic Usage ### Publishers