Skip to content

Commit

Permalink
feat: 미션 인증 및 완료 사진 업로드 단계 예외케이스 처리 (#114)
Browse files Browse the repository at this point in the history
* chore: RedisConfig에 RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP 설정 추가

* feat: MissionRecordTTl, Repository 클래스 생성

* chore: RedisExpireEvent 상수 생성

* feat: RedisExpireEventRedisMessageListener 생성

* chore: RedisMessageListenerConfig 생성

* feat: 미션 일지 생성 후 Redis에 TTL 저장

* fix: TTL 10분으로 설정

* style: spotless

* refactor: EXPIRATION_TIME 상수 적용과 ttl 변수명 변경
  • Loading branch information
kdomo authored Jan 10, 2024
1 parent f9576e9 commit 90807a3
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.depromeet.domain.missionRecord.dao;

import com.depromeet.domain.missionRecord.domain.MissionRecordTTL;
import org.springframework.data.repository.CrudRepository;

public interface MissionRecordTTLRepository extends CrudRepository<MissionRecordTTL, Long> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.depromeet.domain.missionRecord.domain;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.TimeToLive;

@RedisHash("MissionRecordTTL")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MissionRecordTTL {
@Id private String key;

@TimeToLive private Long timeToLive;

@Builder(access = AccessLevel.PRIVATE)
private MissionRecordTTL(String key, Long timeToLive) {
this.key = key;
this.timeToLive = timeToLive;
}

public static MissionRecordTTL createMissionRecordTTL(String key, Long timeToLive) {
return MissionRecordTTL.builder().key(key).timeToLive(timeToLive).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
import com.depromeet.domain.mission.dao.MissionRepository;
import com.depromeet.domain.mission.domain.Mission;
import com.depromeet.domain.missionRecord.dao.MissionRecordRepository;
import com.depromeet.domain.missionRecord.dao.MissionRecordTTLRepository;
import com.depromeet.domain.missionRecord.domain.MissionRecord;
import com.depromeet.domain.missionRecord.domain.MissionRecordTTL;
import com.depromeet.domain.missionRecord.dto.request.MissionRecordCreateRequest;
import com.depromeet.domain.missionRecord.dto.response.MissionRecordFindOneResponse;
import com.depromeet.domain.missionRecord.dto.response.MissionRecordFindResponse;
import com.depromeet.global.common.constants.RedisExpireEventConstants;
import com.depromeet.global.error.exception.CustomException;
import com.depromeet.global.error.exception.ErrorCode;
import com.depromeet.global.util.MemberUtil;
Expand All @@ -22,9 +25,12 @@
@RequiredArgsConstructor
@Transactional
public class MissionRecordService {
private static final int EXPIRATION_TIME = 10;

private final MemberUtil memberUtil;
private final MissionRepository missionRepository;
private final MissionRecordRepository missionRecordRepository;
private final MissionRecordTTLRepository missionRecordTTLRepository;

public Long createMissionRecord(MissionRecordCreateRequest request) {
final Mission mission = findMissionById(request.missionId());
Expand All @@ -39,7 +45,18 @@ public Long createMissionRecord(MissionRecordCreateRequest request) {
MissionRecord missionRecord =
MissionRecord.createMissionRecord(
duration, request.startedAt(), request.finishedAt(), mission);
return missionRecordRepository.save(missionRecord).getId();
Long expirationTime =
Duration.between(
request.finishedAt(),
request.finishedAt().plusMinutes(EXPIRATION_TIME))
.getSeconds();
MissionRecord createdMissionRecord = missionRecordRepository.save(missionRecord);
missionRecordTTLRepository.save(
MissionRecordTTL.createMissionRecordTTL(
RedisExpireEventConstants.EXPIRE_EVENT_IMAGE_UPLOAD_TIME_END.getValue()
+ createdMissionRecord.getId(),
expirationTime));
return createdMissionRecord.getId();
}

private Mission findMissionById(Long missionId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.depromeet.domain.missionRecord.service;

import com.depromeet.domain.missionRecord.dao.MissionRecordRepository;
import com.depromeet.global.common.constants.RedisExpireEventConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
public class RedisExpireEventRedisMessageListener implements MessageListener {
private final MissionRecordRepository missionRecordRepository;

@Override
public void onMessage(Message message, byte[] pattern) {
String patternStr = new String(pattern);
log.info(
"RedisExpireEventRedisMessageListener.onMessage : message = {}, pattern = {}",
message.toString(),
patternStr);
if (!patternStr.equals(RedisExpireEventConstants.REDIS_EXPIRE_EVENT_PATTERN.getValue())) {
return;
}
String event = message.toString().split(":")[1];

if (!event.startsWith(
RedisExpireEventConstants.EXPIRE_EVENT_IMAGE_UPLOAD_TIME_END.getValue())) {
return;
}

Long missionRecordId = Long.valueOf(event.split("_")[6]);
missionRecordRepository.deleteById(missionRecordId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.depromeet.global.common.constants;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum RedisExpireEventConstants {
REDIS_EXPIRE_EVENT_PATTERN("__keyevent@*__:expired"),
EXPIRE_EVENT_IMAGE_UPLOAD_TIME_END("EXPIRE_EVENT_IMAGE_UPLOAD_TIME_END_");
private final String value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisKeyValueAdapter;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;

@EnableRedisRepositories
@EnableRedisRepositories(
enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP)
@Configuration
@RequiredArgsConstructor
public class RedisConfig {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.depromeet.infra.config.redis;

import com.depromeet.domain.missionRecord.service.RedisExpireEventRedisMessageListener;
import com.depromeet.global.common.constants.RedisExpireEventConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

@Configuration
public class RedisMessageListenerConfig {
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(
RedisConnectionFactory redisConnectionFactory,
RedisExpireEventRedisMessageListener redisExpireEventRedisMessageListener) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener(
redisExpireEventRedisMessageListener,
new PatternTopic(RedisExpireEventConstants.REDIS_EXPIRE_EVENT_PATTERN.getValue()));
return container;
}
}

0 comments on commit 90807a3

Please sign in to comment.