Implement distributed event handler to propagate ad deletion

This commit is contained in:
Romain Thouvenin 2024-04-25 15:29:34 +02:00
parent 1701fbbeb1
commit d48d01f051
6 changed files with 94 additions and 4 deletions

View File

@ -15,6 +15,9 @@ export const MATCHER_AD_CREATION_FAILED_ROUTING_KEY =
export const AD_CREATED_MESSAGE_HANDLER = 'adCreated';
export const AD_CREATED_ROUTING_KEY = 'ad.created';
export const AD_CREATED_QUEUE = 'matcher.ad.created';
export const AD_DELETED_MESSAGE_HANDLER = 'adDeleted';
export const AD_DELETED_ROUTING_KEY = 'ad.deleted';
export const AD_DELETED_QUEUE = 'matcher.ad.deleted';
// health
export const GRPC_HEALTH_PACKAGE_NAME = 'health';

View File

@ -43,6 +43,7 @@ import { TimeConverter } from './infrastructure/time-converter';
import { TimezoneFinder } from './infrastructure/timezone-finder';
import { MatchGrpcController } from './interface/grpc-controllers/match.grpc-controller';
import { AdCreatedMessageHandler } from './interface/message-handlers/ad-created.message-handler';
import { AdDeletedMessageHandler } from './interface/message-handlers/ad-deleted.message-handler';
import { MatchMapper } from './match.mapper';
import { MatchingMapper } from './matching.mapper';
@ -97,7 +98,7 @@ const imports = [
const grpcControllers = [MatchGrpcController];
const messageHandlers = [AdCreatedMessageHandler];
const messageHandlers = [AdCreatedMessageHandler, AdDeletedMessageHandler];
const eventHandlers: Provider[] = [
PublishMessageWhenMatcherAdIsCreatedDomainEventHandler,

View File

@ -0,0 +1,32 @@
import { RabbitSubscribe } from '@mobicoop/message-broker-module';
import { DeleteAdCommand } from '@modules/ad/core/application/commands/delete-ad/delete-ad.command';
import { Injectable } from '@nestjs/common';
import { CommandBus } from '@nestjs/cqrs';
import {
AD_DELETED_MESSAGE_HANDLER,
AD_DELETED_ROUTING_KEY,
} from '@src/app.constants';
import { AdReference } from './ad.types';
@Injectable()
export class AdDeletedMessageHandler {
constructor(private readonly commandBus: CommandBus) {}
@RabbitSubscribe({
name: AD_DELETED_MESSAGE_HANDLER,
routingKey: AD_DELETED_ROUTING_KEY,
})
public async adDeleted(message: string): Promise<void> {
try {
const deletedAd: AdReference = JSON.parse(message);
await this.commandBus.execute(
new DeleteAdCommand({
id: deletedAd.aggregateId,
}),
);
} catch (error: any) {
// do not throw error to acknowledge incoming message
// error handling should be done in the command handler, if relevant
}
}
}

View File

@ -1,7 +1,10 @@
import { Frequency } from '@modules/ad/core/domain/ad.types';
export type Ad = {
export type AdReference = {
aggregateId: string;
};
export type Ad = AdReference & {
driver: boolean;
passenger: boolean;
frequency: Frequency;

View File

@ -0,0 +1,44 @@
import { AdDeletedMessageHandler } from '@modules/ad/interface/message-handlers/ad-deleted.message-handler';
import { CommandBus } from '@nestjs/cqrs';
import { Test, TestingModule } from '@nestjs/testing';
const adDeletedMessage =
'{"aggregateId":"4eb6a6af-ecfd-41c3-9118-473a507014d4"}';
const mockCommandBus = {
execute: jest.fn(),
};
describe('Ad Deleted Message Handler', () => {
let adDeletedMessageHandler: AdDeletedMessageHandler;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: CommandBus,
useValue: mockCommandBus,
},
AdDeletedMessageHandler,
],
}).compile();
adDeletedMessageHandler = module.get<AdDeletedMessageHandler>(
AdDeletedMessageHandler,
);
});
afterEach(async () => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(adDeletedMessageHandler).toBeDefined();
});
it('should call the delete command', async () => {
jest.spyOn(mockCommandBus, 'execute');
await adDeletedMessageHandler.adDeleted(adDeletedMessage);
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
});
});

View File

@ -1,17 +1,20 @@
import { Module, Provider } from '@nestjs/common';
import { MESSAGE_PUBLISHER } from './messager.di-tokens';
import {
MessageBrokerModule,
MessageBrokerModuleOptions,
MessageBrokerPublisher,
} from '@mobicoop/message-broker-module';
import { Module, Provider } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import {
AD_CREATED_MESSAGE_HANDLER,
AD_CREATED_QUEUE,
AD_CREATED_ROUTING_KEY,
AD_DELETED_MESSAGE_HANDLER,
AD_DELETED_QUEUE,
AD_DELETED_ROUTING_KEY,
SERVICE_NAME,
} from '@src/app.constants';
import { MESSAGE_PUBLISHER } from './messager.di-tokens';
const imports = [
MessageBrokerModule.forRootAsync({
@ -33,6 +36,10 @@ const imports = [
routingKey: AD_CREATED_ROUTING_KEY,
queue: AD_CREATED_QUEUE,
},
[AD_DELETED_MESSAGE_HANDLER]: {
routingKey: AD_DELETED_ROUTING_KEY,
queue: AD_DELETED_QUEUE,
},
},
}),
}),