Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

문의하기 구글 스프레드시트 API 요청 책임을 클라이언트에서 서버로 변경 #923

Merged
merged 42 commits into from
Dec 10, 2024

Conversation

zeus6768
Copy link
Contributor

@zeus6768 zeus6768 commented Nov 16, 2024

⚡️ 관련 이슈

#851 에 개발 과정이 대략적으로 설명되어 있어요.

📍주요 변경 사항

문의하기(VOC)의 구글 스프레드시트 요청을 서버에서 수행해요.

Global, develop, production 환경의 secret에 VOC 관련 설정값을 추가했어요.

기존 VOC 스프레드시트에 더불어 개발서버용 시트를 만들었어요.

Screenshot 2024-12-02 at 11 51 33 AM

🚨 운영서버와 다른 점

개발서버에서는 문의하기 요청을 해도 이메일을 발송하지 않아요.

고민

Interceptor 테스트

VocServiceTest에서 RestClient의 모든 동작을 검증해요.

1나노초 이상의 시간이 소모되면 timeout을 발생하도록 RestCient Builder를 설정했어요.

해당 빌더로 만드는 MockRestServiceServer에 요청을 보내면, 타임아웃이 발생할 거라고 기대했어요.

그런데 타임아웃이 발생하지 않아서, 인터셉터를 테스트할 수 없었어요.

정상적으로 테스트할 방법을 찾고 싶어요.

로깅

VocConfiguration에서 RestClient Builder를 빈으로 등록했어요.

예외처리 시 로그를 남기고 싶어서 Interceptor, ErrorHandler를 생성하고 등록했어요.

요구사항은 다음과 같아요.

  • IOException, SocketTimeoutException 등 catch문에서 다루는 예외가 발생하면 클라이언트에 500을 응답
  • Stacktrace 로그

Slf4j를 사용해서 로그를 하드코딩했는데, 기존에 만들어진 RequestResponseLogger와 GlobalExceptionHanlder로 적절히 로그를 남길 수 있다면 좋겠다는 생각이 들었어요.

그런데 기존의 logger를 사용할 수 있는지, 만약 사용할 수 있다면 어떻게 사용해야 할지 잘 모르겠어요.

이 부분에서 조언 부탁해요 😭

🍗 PR 첫 리뷰 마감 기한

12/03 23:59

@zeus6768 zeus6768 self-assigned this Nov 16, 2024
@Jaymyong66 Jaymyong66 added feature 기능 추가 BE 백엔드 labels Nov 16, 2024
@Jaymyong66 Jaymyong66 added this to the 7차 스프린트 💭 milestone Nov 16, 2024
@zeus6768
Copy link
Contributor Author

CI 실패 관련 메모

gradle test fast fail

https://blog.mrhaki.com/2019/09/gradle-goodness-stop-build-after-one.html

@zeus6768 zeus6768 marked this pull request as ready for review December 2, 2024 02:43
Copy link
Contributor

@kyum-q kyum-q left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제우스 수고했어요 ~
오랜만에 restClient 보니 어질어질하네요 ~ ㅋㅋㅋ
간단한 코멘트 몇개 남겨뒀으니 확인 부탁드려요 ~

Interceptor 테스트 고민에 대해서는 잘 모르겠네요 ~ 조금 더 고민해볼게요 !
로깅 고민에 대해서는 댓글 달아두었습니다 확인부탁드려요 ~

Copy link
Contributor

@HoeSeong123 HoeSeong123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어렵네요 진짜..
로그 관련해서 계속 고민해봤는데 마땅한 해결책이 생각나지는 않네요.
그래도 현재 방식이 엄청 어색하다고 생각되지는 않습니다!!
나중에 로그 관련 코드를 한 번 정리하면 좋긴 하겠네요.
고생하셨습니다!

Comment on lines +24 to +31
public RestClient.Builder vocRestClientBuilder() {
return RestClient.builder()
.baseUrl(properties.getBaseUrl())
.defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.defaultStatusHandler(new VocResponseErrorHandler())
.requestInterceptor(new VocClientHttpRequestInterceptor())
.requestFactory(requestFactory());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래와 같이 return 타입을 RestClient가 아닌 RestClient.Builder로 한 이유가 있나요??

Suggested change
public RestClient.Builder vocRestClientBuilder() {
return RestClient.builder()
.baseUrl(properties.getBaseUrl())
.defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.defaultStatusHandler(new VocResponseErrorHandler())
.requestInterceptor(new VocClientHttpRequestInterceptor())
.requestFactory(requestFactory());
}
public RestClient vocRestClientBuilder() {
return RestClient.builder()
.baseUrl(properties.getBaseUrl())
.defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.defaultStatusHandler(new VocResponseErrorHandler())
.requestInterceptor(new VocClientHttpRequestInterceptor())
.requestFactory(requestFactory())
.build();
}

Copy link
Contributor Author

@zeus6768 zeus6768 Dec 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확장과 테스트를 위해서 열어 놓았어요.

  • RestClient는 불변이고, Builder는 도메인에 따라 달라지는 설정을 커스텀해서 사용할 수 있어요.
    • 지금은 사용되는 곳이 한 곳 뿐이지만, 이정도 유연성을 가져가는 건 괜찮다고 생각해서 이렇게 작성했어요.
  • 테스트코드에서처럼 MockMvcRestServiceServer를 사용하기 위해서는 RestClient Builder 객체가 필요해요.

혹시 제가 모르는 게 있다면 알려주세요~!

HttpStatusCode statusCode = response.getStatusCode();
return statusCode.isError();
} catch (IOException e) {
log.error(e.getMessage(), e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아무리 생각해도 지금 코드에서 이거 없앨 수 있는 방법이 생각이 안나네요...😭
나중에 에러 처리도 손봐야 할 것 같긴 합니다..

private CredentialManager credentialManager;

@Test
void create() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DisplayName 써주세요!

Copy link
Contributor

@jminkkk jminkkk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제우스 수고했어요 👍
덕분에 문의하기 기능의 완성도가 더 높아지겠네요 :)

리뷰를 남기다보니 조금 많아졌는데,, 찬찬히 확인 부탁해요 ㅎㅎ

}

private ClientHttpRequestFactory requestFactory() {
var httpRequestFactory = new SimpleClientHttpRequestFactory();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제우스 이 PR과 조금 다른 이야기일수도 있긴 한데요! var 변수에 대해 다같이 컨벤션을 논의해보면 좋을 것 같아요.

어떤 변수는 타입 추론이고 어떤 변수는 객체 지정이면 같은 프로젝트 내에서 조금 일관성이 깨질 수도 있을 것 같아요 🥲
추가로 이에 대한 다른 분들 의견도 궁금해요!

backend/src/test/java/codezap/voc/dto/VocRequestTest.java Outdated Show resolved Hide resolved
backend/src/test/java/codezap/voc/dto/VocRequestTest.java Outdated Show resolved Hide resolved
backend/src/test/java/codezap/voc/dto/VocRequestTest.java Outdated Show resolved Hide resolved
Comment on lines +5 to +6
connect-timeout: 5s
read-timeout: 5s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각각 5, 5초로 설정한 이유가 궁금해요!
google sheet api 사용량 한도 공식 문서

sheet api 를 사용한 것이 맞다면, 다음 부분을 참고해보면 좋을 것 같아요 :)

하나의 API 요청 처리 시 최대 시간 제한이 있습니다. Sheets에서 180초가 넘는 시간을 처리하는 경우 요청에서 시간 초과를 반환합니다. 오류가 발생했습니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 좀 헷갈리는 부분인데, 우리는 Google Sheets API를 사용하지 않아요!

대신 Google Apps Script를 사용해요.

Google Apps Script는 Sheets뿐 아니라 Docs와 Slides에서도 개발자가 미리 배포한 자바스크립트를 실행할 수 있게 해줘요.

Google Apps Script문서에는 timeout 권장 시간을 명시한 문서는 없고 Google 서비스 할당량에 따른 6분의 실행 제한만 있어요.

Screenshot 2024-12-06 at 6 03 00 PM

그러나 우리의 Apps Script는 매우 간단하고, 제한을 초과할 일이 거의 없어요.

그래서 제 임의로 너무 길지도 너무 짧지도 않게 5초로 설정했어요.

몰리는 어떻게 설정하는 게 좋다고 생각하나요?

좋은 아이디어가 있다면 얼마든지 제안해주세요~!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 Read Timeout이 5초면 너무 짧지 않을까 싶었어요.
요청이 간단해도 구글 측에 일시적인 부하가 있다면 응답이 느려질 수도 있을 것 같은데, 적절한 값이 나와있지 않아 직접 평균 응답 시간 테스트를 해보지 않는 이상 어렵긴 하네요....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 직접 수차례 테스트했을 땐, 1초 이상의 속도가 걸렸전 적은 없어요.

몰리 말대로 일시적 부하가 있다면 응답에 문제가 있을 수 있지만, 구체적으로 어떤 값으로 정할지 모르겠어서 일단 넘어갈게요!

개인적으로는 관리자 기능을 개발하며 스프레드시트 대신 DB를 사용하도록 바뀌어야 한다고 생각해요 😁

Copy link
Contributor

@HoeSeong123 HoeSeong123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#923 (comment)
이것도 알려주세요😭😭😭

Copy link
Contributor

@jminkkk jminkkk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 제우스~
수고하셨습니다 🔥

대부분의 리뷰가 반영되었는데요. 다음 두 부분이 의견이 작성되어 있지 않아 확인해주시면 바로 approve 할게요!

#923 (comment)

#923 (comment)

Copy link
Contributor Author

@zeus6768 zeus6768 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아뭐야 submit을 안 눌렀네요;; 죄송합니다 🙇‍♂️

한 번 더 검토하고 다시 요청할게요!

Comment on lines +5 to +6
connect-timeout: 5s
read-timeout: 5s
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 좀 헷갈리는 부분인데, 우리는 Google Sheets API를 사용하지 않아요!

대신 Google Apps Script를 사용해요.

Google Apps Script는 Sheets뿐 아니라 Docs와 Slides에서도 개발자가 미리 배포한 자바스크립트를 실행할 수 있게 해줘요.

Google Apps Script문서에는 timeout 권장 시간을 명시한 문서는 없고 Google 서비스 할당량에 따른 6분의 실행 제한만 있어요.

Screenshot 2024-12-06 at 6 03 00 PM

그러나 우리의 Apps Script는 매우 간단하고, 제한을 초과할 일이 거의 없어요.

그래서 제 임의로 너무 길지도 너무 짧지도 않게 5초로 설정했어요.

몰리는 어떻게 설정하는 게 좋다고 생각하나요?

좋은 아이디어가 있다면 얼마든지 제안해주세요~!

backend/src/main/resources/application.yml Outdated Show resolved Hide resolved
Copy link
Contributor

@kyum-q kyum-q left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제우스 수고하셨습니다~!!!

Copy link
Contributor

@jminkkk jminkkk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제우스 수고했어요! 🔥🔥

@zeus6768 zeus6768 merged commit 4dc5328 into dev/be Dec 10, 2024
11 checks passed
@zeus6768 zeus6768 deleted the feat/851-voc branch December 10, 2024 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BE 백엔드 feature 기능 추가
Projects
Status: Weekend Done
Development

Successfully merging this pull request may close these issues.

6 participants