Skip to content

Commit

Permalink
🚑 hotfix: redis 저장 에러
Browse files Browse the repository at this point in the history
  • Loading branch information
gomin0 committed Sep 17, 2024
1 parent 138c0ce commit 7cb9976
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 45 deletions.
2 changes: 0 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ dependencies {
//firebase
implementation 'com.google.firebase:firebase-admin:9.2.0'

implementation 'org.redisson:redisson-spring-boot-starter:3.27.0'

//S3
implementation group: 'io.awspring.cloud', name: 'spring-cloud-starter-aws', version: '2.4.4'
implementation group: 'io.awspring.cloud', name: 'spring-cloud-starter-aws-secrets-manager-config', version: '2.4.4'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class Profile extends BaseEntity {
@Column(name = "profile_id")
private Long id;

@Column(name = "nickname", nullable = false, length = 20)
@Column(name = "nickname", nullable = false, unique = true, length = 20)
private String nickname; // 닉네임

@Column(name = "profile_image_url")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
Expand All @@ -32,6 +34,7 @@ public class AccountsService {
private final JwtProvider jwtProvider;
private final RedisUtil redisUtil;
private final AccountsCommonService accountsCommonService;
private static final Logger logger = LoggerFactory.getLogger(AccountsService.class);

public UserLoginResponseDto login(UserLoginRequestDto requestDto) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

@RequiredArgsConstructor
@Service
Expand All @@ -29,36 +26,12 @@ public class FcmNotificationService {
private final UserJpaRepository userJpaRepository;
private final RedisUtil redisUtil;
private final FcmNotificationRepository fcmNotificationRepository;
private final RedissonClient redissonClient;

private static final String LOCK_PREFIX = "fcm_notification:";

// 항상 새로운 트랜잭션에서 실행
@Transactional(propagation = Propagation.REQUIRES_NEW)
public FcmNotification saveNotification(FcmNotificationRequestDto requestDto, User user) {
String lockKey = LOCK_PREFIX + user.getId();
RLock lock = redissonClient.getLock(lockKey);

try {
// 5초 동안 락 획득 시도, 획득 성공 시 최대 10초 동안 락 유지 => 데드락 방지

if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
try {
FcmNotification fcmNotification = requestDto.toEntity(user);
return fcmNotificationRepository.save(fcmNotification);
} finally {
// 작업 완료 후 즉시 락 해제 시도
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} else {
throw new FcmNotificationExceptionHandler(ErrorCode.LOCK_ACQUISITION_FAILED);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new FcmNotificationExceptionHandler(ErrorCode.NOTIFICATION_SAVE_FAILED);
}
FcmNotification fcmNotification = requestDto.toEntity(user);
return fcmNotificationRepository.save(fcmNotification);
}

// 트랜잭션 없이 실행
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.capstone.BnagFer.global.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -34,10 +31,4 @@ public RedisTemplate<String, Object> redisTemplate() {
return redisTemplate;
}

@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://" + redisHost + ":" + redisPort);
return Redisson.create(config);
}
}
11 changes: 7 additions & 4 deletions src/main/java/com/capstone/BnagFer/global/util/RedisUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@RequiredArgsConstructor
public class RedisUtil {
private final RedisTemplate<String, Object> redisTemplate;
private static final String FCM_TOKEN_PREFIX = "fcm:token:";
private static final long ONE_WEEK_IN_SECONDS = 7 * 24 * 60 * 60; // 일주일을 초로 표현

public void save(String key, Object val, Long time, TimeUnit timeUnit) {
Expand Down Expand Up @@ -68,12 +69,13 @@ public boolean delete(String key) {
}

public void saveFCMToken(String userEmail, String fcmToken) {
redisTemplate.opsForValue().set(userEmail, fcmToken);
redisTemplate.expire(userEmail, 30, TimeUnit.DAYS);
String key = FCM_TOKEN_PREFIX + userEmail;
redisTemplate.opsForValue().set(key, fcmToken, 30, TimeUnit.DAYS);
}

public String getFCMToken(String userEmail) {
Object tokenObj = redisTemplate.opsForValue().get(userEmail);
String key = FCM_TOKEN_PREFIX + userEmail;
Object tokenObj = redisTemplate.opsForValue().get(key);
if (tokenObj != null) {
return (String) tokenObj;
} else {
Expand All @@ -82,6 +84,7 @@ public String getFCMToken(String userEmail) {
}

public void removeFCMToken(String userEmail) {
redisTemplate.delete(userEmail);
String key = FCM_TOKEN_PREFIX + userEmail;
redisTemplate.delete(key);
}
}

0 comments on commit 7cb9976

Please sign in to comment.