[Nest.js] 왜.. 호출 한 번에 로그 두 번이 찍힐까요? - 1 (과정)

초이지수·2023년 8월 3일
0

Nest.js

목록 보기
8/14
post-custom-banner

winston으로

  1. 로그인 로그
  2. 사용자 정보 조회 시 로그

총 두 개의 로그를 파일로 저장하는 코드를 작성했다.

그런데 왜 와이? 로그인 로그는 호출 한 번에 로그 한 번인데, 사용자 정보 조회 로그는 호출 한 번에 로그가 두 번 찍혔다..? 원인을 찾아보자!


📌 1. winston 코드가 문제인가?(아님)

일단 제일 먼저! 로그와 관련된 코드가 있는 LoggerService 코드를 살펴보았다.

아무리 살펴봐도 두 번 호출 되는 곳이 없는 것 같았다. 만약에 이 코드에 문제가 있어서 두 번 호출 되는 것이라면 로그인 로그도 두 번 찍혀야 하는데, 로그인 로그는 멀쩡하게 호출 한 번에 로그 한 번이 찍혔기 때문이다.

그럼 사용자 조회와 관련된 코드에서 문제가 발생하는 건가? controller와 service 코드를 살펴보자!


📌 2. getUserInfo 코드가 문제인가? (맞음)

📎 users.controller.ts

🖇 getUserInfo

🖇 login

service 코드를 먼저 살펴보기 전에, 로그인과 사용자 정보 조회 controller 코드의 차이점 위주로 살펴보았다. getUserInfo controller 코드에는 데코레이터가 많이 붙어있었다. 오... 이것이 문제인 것 같다.. 느낌이 온다...


📎 1. @UseGuards(JwtAuthGuard)

@UseGuards는 @nestjs/common 에서 제공되는 데코레이터이다. 특정 라우트 핸들러에 guard를 첨부하는데 사용된다. 가드는 라우트를 보호하고 특정 조건에 따라 액세스를 제한하는데 사용된다.
JwtAuthGuard는 JWT인증을 구현한 커스텀 가드이다. 유효한 JWT토큰이 요청의 Authorization 헤더에 있을 때만 요청이 인증 된다.


📎 2. @GetUserJWT

@GetUserJWT는 @nestjs/common의 createParamDecorator를 사용해 만든 커스텀 데코레이터이다. 커스텀 데코레이터는 요청으로부터 추가 정보를 추출하고 이를 라우트 핸들러의 인수로 전달하는데 사용된다. 여기에서는 @GetUserJWT가 인증된 사용자의 정보(AuthUserType으로 정의된 사용자의 id)를 요청의 user 속성에서 추출한다. 추출된 사용자 정보는 컨트롤러의 getUserInfo 메서드에 인수로 전달되고, 최종적으로 사용자의 정보를 얻을 수 있게 되는 것이다!


@UseGuards(JwtAuthGuard)사용자의 인증을 위한 코드이고, @GetUserJWT는 요청에서 인증된 사용자의 정보(사용자 id)를 추출해 컨트롤러의 getUserInfo 메서드에 인수로 전달해주는 코드이다.

이렇게 서로 다른 역할로 두 번 호출되는 것이었다...!

오... 서로 다른 역할이어도,, 한 번 호출 하면 안 되나..? 두 개 다 사용자 관련 호출인데 한 번 요청에 두 번 호출은 너무 비효율 적인데,,..

다른 방법이 없을까? 고민하던 중, 사용자 정보를 한 번 가져온 후 그 정보를 메모리에 저장하고 재사용 하는 캐싱(Caching) 방법을 이용해 보기로 했다!


📌 캐싱을 사용해 보자!

세 번째 글을 확인하면 알 수 있지만,,, 여기서 캐싱을 사용할 필요가 없다.
그래도! 문제를 해결해나가는 과정 중에 하나였으니 글은 이대로 유지하려고 한다.

🖇 수정 전 JwtStrategy


🖇 수정 후 JwtStrategy

처음에는 cache-manager 패키지를 설치해서 코드를 작성하려고 했는데, CACHE_MANAGER를 @nestjs/common에서 import하니 줄이 쫙 ... 갔다.. 이제는 사용 못 한다는 뜻

그래서 위와 같이 모듈이 아닌, 간단하게 메모리에 변수를 저장해 사용자 정보를 캐싱하는 코드를 작성했다.

JwtStrategy 클래스 내부에 사용자 정보를 메모리에 저장하고, 컨트롤러의 getUserInfo 메서드에서 먼저 메모리를 확인하고 없을 경우에만 데이터베이스에서 가져오도록 수정했다.

Map 자료구조를 사용한 이유는 key-value 값을 쌍으로 저장해 데이터를 검색하는데 효율적이고, set 메서드를 이용해 key-value 값을 쌍으로 쉽게 저장할 수 있기 때문이다.

이제 컨트롤러에서도 사용자 정보를 더 이상 호출하지 않고 캐시된 정보를 사용할 수 있다! 캐싱을 통해 데이터베이스 호출 횟수를 줄여 성능을 개선 & 불필요한 로그 두 번 찍힘 현상을 개선 했다!


🥲 절반... 의 성공

처음에는 로그가 두 번 찍히고,.. 그 다음 부터는 한 번씩 찍혔다... 왜 와이? 처음부터 한 번씩 찍혀주세요,, 무엇이 또 문제인가아 🤔


캐싱에 대해 구글링을 해보았다.

메모리에 저장되는 데이터는 앱이 실행되는 동안에만 유지되고, 앱을 재시작하면 데이터가 사라진다

라는 내용이 있었다... (?) 맞네 메모리는 휘발성인데 이래서 앱을 꼈다가 다시 키면 두 번씩 찍히는 거였구나? 영구적으로 데이터를 보존해야 하는 경우에는 데이터베이스와 같은 영구적인 저장소를 사용해야지요...

영구적인 저장소.. 투 비 컨티뉴,,

profile
닫혀 있어서 벽인 줄 알고 있지만, 사실은 문이다.
post-custom-banner

0개의 댓글