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 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(