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

[Feature/#243] 디스코드 알림 연동 #247

Merged
merged 11 commits into from
Oct 24, 2024
9 changes: 9 additions & 0 deletions linkmind/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ dependencies {

implementation 'io.sentry:sentry-spring-boot-starter:5.7.0'

// openfeign
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

}

dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:2023.0.3")
}
}
//sourceSets {
// main {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cglib.core.Local;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import javax.annotation.PostConstruct;
import java.time.LocalTime;
import java.util.TimeZone;

@SpringBootApplication
@EnableFeignClients
@EnableJpaAuditing
public class ToasterApplication {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public enum Error {
CREATE_PUBLIC_KEY_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "publickey 생성 과정 중 문제가 발생했습니다."),
FAIL_TO_SEND_PUSH_ALARM(HttpStatus.INTERNAL_SERVER_ERROR, "다수기기 푸시메시지 전송 실패"),
FAIL_TO_SEND_SQS(HttpStatus.INTERNAL_SERVER_ERROR, "sqs 전송 실패"),
INVALID_DISCORD_MESSAGE(HttpStatus.INTERNAL_SERVER_ERROR, "디스코드 알림 전송 실패"),

CREATE_TOAST_PROCCESS_EXCEPTION(HttpStatus.INTERNAL_SERVER_ERROR, "토스트 저장 중 문제가 발생했습니다. 카테고리 또는 s3 관련 문제로 예상됩니다.")
;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.app.toaster.external.client.discord;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient(name = "${discord.name}", url = "${discord.webhook-url}")
public interface DiscordClient {
@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
void sendMessage(@RequestBody DiscordMessage discordMessage);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.app.toaster.external.client.discord;

import java.util.List;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class DiscordMessage {

private String content;
private List<Embed> embeds;

@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public static class Embed {

private String title;
private String description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.app.toaster.external.client.discord;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.context.ApplicationContextException;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;

import com.app.toaster.exception.Error;
import com.app.toaster.exception.model.CustomException;
import com.app.toaster.infrastructure.UserRepository;

import feign.FeignException;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Component
public class DiscordMessageProvider {
private final DiscordClient discordClient;
private final UserRepository userRepository;

public void sendSignUpNotification() {
sendMessageToDiscord(createSingUpMessage());
}

private void sendMessageToDiscord(DiscordMessage discordMessage) {
try {
discordClient.sendMessage(discordMessage);
} catch (FeignException e) {
throw new CustomException(Error.INVALID_DISCORD_MESSAGE, Error.INVALID_APPLE_IDENTITY_TOKEN.getMessage());
}
}

private DiscordMessage createSingUpMessage() {
Copy link
Contributor

Choose a reason for hiding this comment

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

옹 좋은데 SignUpMessage()로 오타정도만 나중에 수정해주면 좋을거같네용☺️

return DiscordMessage.builder()
.content("# 😍 회원가입 이벤트가 발생했습니다.")
.embeds(
List.of(
DiscordMessage.Embed.builder()
.title("ℹ️ 회원가입 정보")
.description(
"### 🕖 발생 시간\n"
+ LocalDateTime.now()
+ "\n"
+ "### 📜 유저 가입 정보\n"
+ "토스터의 " + userRepository.count() + "번째 유저가 생성되었습니다!! ❤️"
+ "\n")
.build()
)
)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.app.toaster.service.auth;

import java.io.IOException;
import java.time.LocalDateTime;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.WebRequest;

import com.app.toaster.common.dto.ApiResponse;
import com.app.toaster.config.jwt.JwtService;
Expand All @@ -21,6 +23,8 @@
import com.app.toaster.exception.model.CustomException;
import com.app.toaster.exception.model.NotFoundException;
import com.app.toaster.exception.model.UnprocessableEntityException;
import com.app.toaster.external.client.discord.DiscordMessage;
import com.app.toaster.external.client.discord.DiscordMessageProvider;
import com.app.toaster.external.client.slack.SlackApi;
import com.app.toaster.infrastructure.CategoryRepository;
import com.app.toaster.infrastructure.TimerRepository;
Expand Down Expand Up @@ -48,6 +52,7 @@ public class AuthService {
private final PopupManagerRepository popupManagerRepository;

private final SlackApi slackApi;
Copy link
Contributor

Choose a reason for hiding this comment

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

이렇게 되면 SlackApi도 같이 이 pr에서 제거해주실 수 있을까용?🐱

Copy link
Member Author

Choose a reason for hiding this comment

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

혹시 SlackApi 관련 클래스 모두 삭제하는것을 말하는걸까요...?

Copy link
Contributor

Choose a reason for hiding this comment

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

아 흠 클래스까지 다 지우기에 좀.. 그렇네용 아까운뎅 ㅜ 일단 보류하는거 어떻게 생각하시나용;?ㅋㅋ 줏대 없어서 죄송합니당😢

private final DiscordMessageProvider discordMessageProvider;


private final Long TOKEN_EXPIRATION_TIME_ACCESS = 7*24*60 * 60 * 1000L; //7일
Expand Down Expand Up @@ -76,7 +81,8 @@ public SignInResponseDto signIn(String socialAccessToken, SignInRequestDto reque
.socialType(socialType).build();
newUser.updateFcmIsAllowed(true); //신규 유저면 true박고
userRepository.save(newUser);
slackApi.sendSuccess(Success.LOGIN_SUCCESS);
// slackApi.sendSuccess(Success.LOGIN_SUCCESS);
discordMessageProvider.sendSignUpNotification();
Copy link
Contributor

Choose a reason for hiding this comment

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

흠 여기서 궁금한게
우리가 회원가입을 할 때 저거 publish 메시지를 하고? 그 publish message하는 것도 트랜잭션에 묶이고 있는데, 해당 publish message가 private 메서드만 호출하고 오류는 private 메서드 내에서 에러가 난다면 그건 회원가입 트랜잭션에 영향이 안가는건지 궁금합니다!

최근 트랜잭션 전파단계에 대해서 공부하긴했었는데 실제로 사례로보니 더 헷갈리는거같네용 ㅠ

Copy link
Member Author

@mmihye mmihye Oct 16, 2024

Choose a reason for hiding this comment

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

엇 그러고 보니 알림에서 에러가 나면 모든로직이 롤백될거같네요...
같은 클래스내 private 메서드면 영향이 없는걸로 아는데 sendSignUpNotification public 메소드라서 영향이 있겠네요...

81f6717 다음과 같이 Try-Catch 문을 사용하여 에러 발생하면 로그찍고넘어가는 걸로 고쳐봤는데 이렇게하면 괜찮을까요? 혹시 좋은방법이나 아이디어있으시면 말씀해주세용

Copy link
Contributor

@sss4920 sss4920 Oct 16, 2024

Choose a reason for hiding this comment

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

흠.. 일단 로그찍는것도 임시방편으로 나쁘지않은 것 같습니다!!

약간 아이디어는 트랜잭션을 분리시키는 방법이 있을 것 같긴합니다..!
@transactional에서 전파 옵션에서 required_new라는 애가 있는데 사용하면 외부 트랜잭션과 별도의 새로운 트랜잭션을 시작해서 처리하는 것으로 알고있습니당!
대신에 앞에 단계가 처리되고 난 후에 동작해야돼서 after_commit이라는 옵션이 더 필요할 것 같아요!

[관련링크]
https://velog.io/@guswns3371/TransactionalEventListener-%EC%82%AC%EC%9A%A9%EC%8B%9C-%EC%A3%BC%EC%9D%98%ED%95%A0-%EA%B2%83

일단 우리단과 비슷한 경우인 듯합니당.
먼저 우리가 save를 통해서 회원가입을 진행하고?
이 트랜잭션 커밋이후에 작동하도록 after_commit을 진행하는데 이 때, after_commit은 이전 트랜잭션 이후에 추가적인 상황에 해당하므로 required_new라는 애를 통해 새로운 트랜잭션을 파서 처리하면 좋을 것 같습니당! 어떻게 생각하시나욤?!☺️

Copy link
Member Author

Choose a reason for hiding this comment

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

옹 새로운 방식이네요 한번 공부해보고 적용해보겠습니다!

}

User user = userRepository.findBySocialIdAndSocialType(socialId, socialType)
Expand Down Expand Up @@ -167,4 +173,5 @@ public TokenHealthDto checkHealthOfToken(String refreshToken){
return TokenHealthDto.of(jwtService.verifyToken(refreshToken));
}


}