mirror of
https://gitlab.com/mobicoop/v3/service/matcher.git
synced 2025-12-31 06:52:40 +00:00
refactor to ddh, first commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { Controller } from '@nestjs/common';
|
||||
import { GrpcMethod } from '@nestjs/microservices';
|
||||
import { RepositoriesHealthIndicatorUseCase } from '../../domain/usecases/repositories.health-indicator.usecase';
|
||||
|
||||
enum ServingStatus {
|
||||
UNKNOWN = 0,
|
||||
SERVING = 1,
|
||||
NOT_SERVING = 2,
|
||||
}
|
||||
|
||||
interface HealthCheckRequest {
|
||||
service: string;
|
||||
}
|
||||
|
||||
interface HealthCheckResponse {
|
||||
status: ServingStatus;
|
||||
}
|
||||
|
||||
@Controller()
|
||||
export class HealthServerController {
|
||||
constructor(
|
||||
private readonly repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase,
|
||||
) {}
|
||||
|
||||
@GrpcMethod('Health', 'Check')
|
||||
async check(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
data: HealthCheckRequest,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
metadata: any,
|
||||
): Promise<HealthCheckResponse> {
|
||||
const healthCheck = await this.repositoriesHealthIndicatorUseCase.isHealthy(
|
||||
'repositories',
|
||||
);
|
||||
return {
|
||||
status:
|
||||
healthCheck['repositories'].status == 'up'
|
||||
? ServingStatus.SERVING
|
||||
: ServingStatus.NOT_SERVING,
|
||||
};
|
||||
}
|
||||
}
|
||||
37
old/modules/health/adapters/primaries/health.controller.ts
Normal file
37
old/modules/health/adapters/primaries/health.controller.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Controller, Get, Inject } from '@nestjs/common';
|
||||
import {
|
||||
HealthCheckService,
|
||||
HealthCheck,
|
||||
HealthCheckResult,
|
||||
} from '@nestjs/terminus';
|
||||
import { MESSAGE_PUBLISHER } from 'src/app.constants';
|
||||
import { IPublishMessage } from 'src/interfaces/message-publisher';
|
||||
import { RepositoriesHealthIndicatorUseCase } from '../../domain/usecases/repositories.health-indicator.usecase';
|
||||
|
||||
@Controller('health')
|
||||
export class HealthController {
|
||||
constructor(
|
||||
private readonly repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase,
|
||||
private healthCheckService: HealthCheckService,
|
||||
@Inject(MESSAGE_PUBLISHER)
|
||||
private readonly messagePublisher: IPublishMessage,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@HealthCheck()
|
||||
async check() {
|
||||
try {
|
||||
return await this.healthCheckService.check([
|
||||
async () =>
|
||||
this.repositoriesHealthIndicatorUseCase.isHealthy('repositories'),
|
||||
]);
|
||||
} catch (error) {
|
||||
const healthCheckResult: HealthCheckResult = error.response;
|
||||
this.messagePublisher.publish(
|
||||
'logging.user.health.crit',
|
||||
JSON.stringify(healthCheckResult.error),
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
old/modules/health/adapters/primaries/health.proto
Normal file
21
old/modules/health/adapters/primaries/health.proto
Normal file
@@ -0,0 +1,21 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package health;
|
||||
|
||||
|
||||
service Health {
|
||||
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
|
||||
}
|
||||
|
||||
message HealthCheckRequest {
|
||||
string service = 1;
|
||||
}
|
||||
|
||||
message HealthCheckResponse {
|
||||
enum ServingStatus {
|
||||
UNKNOWN = 0;
|
||||
SERVING = 1;
|
||||
NOT_SERVING = 2;
|
||||
}
|
||||
ServingStatus status = 1;
|
||||
}
|
||||
16
old/modules/health/adapters/secondaries/message-publisher.ts
Normal file
16
old/modules/health/adapters/secondaries/message-publisher.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { MESSAGE_BROKER_PUBLISHER } from '../../../../app.constants';
|
||||
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
|
||||
import { IPublishMessage } from 'src/interfaces/message-publisher';
|
||||
|
||||
@Injectable()
|
||||
export class MessagePublisher implements IPublishMessage {
|
||||
constructor(
|
||||
@Inject(MESSAGE_BROKER_PUBLISHER)
|
||||
private readonly messageBrokerPublisher: MessageBrokerPublisher,
|
||||
) {}
|
||||
|
||||
publish = (routingKey: string, message: string): void => {
|
||||
this.messageBrokerPublisher.publish(routingKey, message);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface ICheckRepository {
|
||||
healthCheck(): Promise<boolean>;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
HealthCheckError,
|
||||
HealthIndicator,
|
||||
HealthIndicatorResult,
|
||||
} from '@nestjs/terminus';
|
||||
import { ICheckRepository } from '../interfaces/check-repository.interface';
|
||||
import { AdRepository } from '../../../ad/adapters/secondaries/ad.repository';
|
||||
|
||||
@Injectable()
|
||||
export class RepositoriesHealthIndicatorUseCase extends HealthIndicator {
|
||||
private checkRepositories: ICheckRepository[];
|
||||
constructor(private readonly adRepository: AdRepository) {
|
||||
super();
|
||||
this.checkRepositories = [adRepository];
|
||||
}
|
||||
isHealthy = async (key: string): Promise<HealthIndicatorResult> => {
|
||||
try {
|
||||
await Promise.all(
|
||||
this.checkRepositories.map(
|
||||
async (checkRepository: ICheckRepository) => {
|
||||
await checkRepository.healthCheck();
|
||||
},
|
||||
),
|
||||
);
|
||||
return this.getStatus(key, true);
|
||||
} catch (e: any) {
|
||||
throw new HealthCheckError('Repository', {
|
||||
repository: e.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
28
old/modules/health/health.module.ts
Normal file
28
old/modules/health/health.module.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HealthServerController } from './adapters/primaries/health-server.controller';
|
||||
import { DatabaseModule } from '../database/database.module';
|
||||
import { HealthController } from './adapters/primaries/health.controller';
|
||||
import { TerminusModule } from '@nestjs/terminus';
|
||||
import { MESSAGE_BROKER_PUBLISHER, MESSAGE_PUBLISHER } from 'src/app.constants';
|
||||
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
|
||||
import { MessagePublisher } from './adapters/secondaries/message-publisher';
|
||||
import { RepositoriesHealthIndicatorUseCase } from './domain/usecases/repositories.health-indicator.usecase';
|
||||
import { AdRepository } from '../ad/adapters/secondaries/ad.repository';
|
||||
|
||||
@Module({
|
||||
imports: [TerminusModule, DatabaseModule],
|
||||
controllers: [HealthServerController, HealthController],
|
||||
providers: [
|
||||
RepositoriesHealthIndicatorUseCase,
|
||||
AdRepository,
|
||||
{
|
||||
provide: MESSAGE_BROKER_PUBLISHER,
|
||||
useClass: MessageBrokerPublisher,
|
||||
},
|
||||
{
|
||||
provide: MESSAGE_PUBLISHER,
|
||||
useClass: MessagePublisher,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class HealthModule {}
|
||||
36
old/modules/health/tests/unit/message-publisher.spec.ts
Normal file
36
old/modules/health/tests/unit/message-publisher.spec.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { MessagePublisher } from '../../adapters/secondaries/message-publisher';
|
||||
import { MESSAGE_BROKER_PUBLISHER } from '../../../../app.constants';
|
||||
|
||||
const mockMessageBrokerPublisher = {
|
||||
publish: jest.fn().mockImplementation(),
|
||||
};
|
||||
|
||||
describe('Messager', () => {
|
||||
let messagePublisher: MessagePublisher;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [],
|
||||
providers: [
|
||||
MessagePublisher,
|
||||
{
|
||||
provide: MESSAGE_BROKER_PUBLISHER,
|
||||
useValue: mockMessageBrokerPublisher,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
messagePublisher = module.get<MessagePublisher>(MessagePublisher);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(messagePublisher).toBeDefined();
|
||||
});
|
||||
|
||||
it('should publish a message', async () => {
|
||||
jest.spyOn(mockMessageBrokerPublisher, 'publish');
|
||||
messagePublisher.publish('health.info', 'my-test');
|
||||
expect(mockMessageBrokerPublisher.publish).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { HealthCheckError, HealthIndicatorResult } from '@nestjs/terminus';
|
||||
import { RepositoriesHealthIndicatorUseCase } from '../../domain/usecases/repositories.health-indicator.usecase';
|
||||
import { AdRepository } from '../../../ad/adapters/secondaries/ad.repository';
|
||||
|
||||
const mockAdRepository = {
|
||||
healthCheck: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => {
|
||||
return Promise.resolve(true);
|
||||
})
|
||||
.mockImplementation(() => {
|
||||
throw new Error('an error occured in the repository');
|
||||
}),
|
||||
};
|
||||
|
||||
describe('RepositoriesHealthIndicatorUseCase', () => {
|
||||
let repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
RepositoriesHealthIndicatorUseCase,
|
||||
{
|
||||
provide: AdRepository,
|
||||
useValue: mockAdRepository,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
repositoriesHealthIndicatorUseCase =
|
||||
module.get<RepositoriesHealthIndicatorUseCase>(
|
||||
RepositoriesHealthIndicatorUseCase,
|
||||
);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(repositoriesHealthIndicatorUseCase).toBeDefined();
|
||||
});
|
||||
|
||||
describe('execute', () => {
|
||||
it('should check health successfully', async () => {
|
||||
const healthIndicatorResult: HealthIndicatorResult =
|
||||
await repositoriesHealthIndicatorUseCase.isHealthy('repositories');
|
||||
|
||||
expect(healthIndicatorResult['repositories'].status).toBe('up');
|
||||
});
|
||||
|
||||
it('should throw an error if database is unavailable', async () => {
|
||||
await expect(
|
||||
repositoriesHealthIndicatorUseCase.isHealthy('repositories'),
|
||||
).rejects.toBeInstanceOf(HealthCheckError);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user