-
Notifications
You must be signed in to change notification settings - Fork 0
인터셉터로 관심사 분리하기
mintaek edited this page Dec 1, 2024
·
7 revisions
nest에는 핵심 컴포넌트 중 하나인 인터셉터는 다른 컴포넌트와 다르게 요청과 응답 두 군데서 호출이 됩니다.
이를 특징을 통해 데이터 전처리,로깅,모니터링,캐싱등 다양한 용도로 사용되는데 이에 국한되지 않고 중복되는 특정 로직 또한 가능합니다.
sequenceDiagram
participant 사용자 as 사용자(Client)
participant 컨트롤러 as Controller
participant 서비스 as Service
participant 쿼리서비스 as QueryService
participant 데이터베이스 as Database
사용자->>컨트롤러: 요청 전송 (sessionID 포함)
컨트롤러->>서비스: 요청 전달
서비스->>데이터베이스: 세션 ID로 DB 연결 생성
alt 연결 성공
서비스->>데이터베이스: 트랜잭션 시작
서비스->>쿼리서비스: 비즈니스 로직 전달
쿼리서비스->>데이터베이스: 쿼리 실행
alt 쿼리 성공
쿼리서비스->>서비스: 실행 결과 반환
서비스->>데이터베이스: 트랜잭션 커밋
서비스->>컨트롤러: 처리 결과 반환
컨트롤러->>사용자: 최종 응답 반환
else 쿼리 실패
쿼리서비스->>서비스: 에러 반환
서비스->>데이터베이스: 트랜잭션 롤백
서비스->>컨트롤러: 에러 반환
컨트롤러->>사용자: 에러 응답 반환
end
else 연결 실패 (에러 1040)
서비스->>컨트롤러: "현재 사용자가 많습니다" 에러 반환
컨트롤러->>사용자: 에러 응답 반환
end
서비스->>데이터베이스: DB 연결 종료
sequenceDiagram
participant 사용자 as 사용자(Client)
participant 인터셉터 as UserDBConnectionInterceptor
participant 데이터베이스 as Database
participant 컨트롤러 as Controller
사용자->>인터셉터: 요청 전송 (sessionID 포함)
인터셉터->>데이터베이스: 세션 ID로 DB 연결 생성
alt 연결 성공
인터셉터->>데이터베이스: 트랜잭션 시작
인터셉터->>컨트롤러: 요청 전달
컨트롤러->>인터셉터: 응답 반환
인터셉터->>데이터베이스: 트랜잭션 커밋
else 연결 실패 (에러 1040)
인터셉터->>사용자: "현재 사용자가 많습니다" 에러 반환
end
alt 컨트롤러에서 예외 발생
인터셉터->>데이터베이스: 트랜잭션 롤백
인터셉터->>사용자: 에러 응답 반환
end
인터셉터->>데이터베이스: DB 연결 종료
인터셉터->>사용자: 최종 응답 반환
@Injectable()
export class UserDBConnectionInterceptor implements NestInterceptor {
constructor(private readonly configService: ConfigService) {}
async intercept(
context: ExecutionContext,
next: CallHandler,
): Promise<Observable<any>> {
const request = context.switchToHttp().getRequest();
const identify = request.sessionID;
try {
request.dbConnection = await createConnection({
host: this.configService.get<string>('QUERY_DB_HOST'),
user: identify.substring(0, 10),
password: identify,
port: this.configService.get<number>('QUERY_DB_PORT', 3306),
database: identify,
infileStreamFactory: (path) => {
return createReadStream(path);
},
});
} catch (error) {
console.error('커넥션 제한으로 인한 에러', error);
if (error.errno == 1040) {
throw new HttpException(
{
status: HttpStatus.TOO_MANY_REQUESTS,
message: 'Too many users right now! Please try again soon.',
},
HttpStatus.TOO_MANY_REQUESTS,
);
}
}
await request.dbConnection.query('set profiling = 1');
await request.dbConnection.beginTransaction();
return next.handle().pipe(
tap(async () => {
await request.dbConnection.commit();
}),
catchError(async (err) => {
if (err instanceof DataLimitExceedException) {
await request.dbConnection.rollback();
throw err;
}
}),
finalize(async () => await request.dbConnection.end()),
);
}
}