Skip to content

Commit dbcc2cd

Browse files
refactor: 대기열 redis->db 롤백 로직, 사용자 대기열 상태 확인 로직 리팩토링
* refactor: /{eventId}/exists entered만 확인하도록 변경 * refactor: redis->db 로직 수정 * feat: 로그인/회원가입 기본 데이터 세팅 * refactor: isUserEntered 로직 수정 * refactor: 스케줄러 롤백
1 parent 176ea9f commit dbcc2cd

13 files changed

Lines changed: 197 additions & 30 deletions

File tree

backend/src/main/java/com/back/api/auth/dto/request/LoginRequest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ public record LoginRequest(
1010
@NotBlank(message = "이메일을 입력해주세요.")
1111
@Email(message = "이메일 형식이 올바르지 않습니다.")
1212
@Size(max = 100)
13+
@Schema(
14+
description = "이메일",
15+
example = "test@test.com"
16+
)
1317
String email,
1418

1519
@NotBlank(message = "비밀번호를 입력해주세요.")
1620
@Size(min = 8, max = 30, message = "비밀번호는 8~30 글자여야 합니다.")
21+
@Schema(
22+
description = "비밀번호",
23+
example = "abc12345"
24+
)
1725
String password
1826
) {
1927
}

backend/src/main/java/com/back/api/auth/dto/request/SignupRequest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,18 @@ public record SignupRequest(
1313
@NotBlank(message = "이메일은 필수입니다.")
1414
@Email(message = "이메일 형식이 올바르지 않습니다.")
1515
@Size(max = 100)
16+
@Schema(
17+
description = "이메일",
18+
example = "test@test.com"
19+
)
1620
String email,
1721

1822
@NotBlank(message = "비밀번호는 필수입니다.")
1923
@Size(min = 8, max = 30, message = "비밀번호는 8~30 글자여야 합니다.")
24+
@Schema(
25+
description = "비밀번호",
26+
example = "abc12345"
27+
)
2028
String password,
2129

2230
@NotBlank(message = "이름은 필수입니다.")

backend/src/main/java/com/back/api/auth/dto/response/UserResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public record UserResponse(
1414

1515
@Schema(
1616
description = "사용자 이메일",
17-
example = "user@example.com",
17+
example = "test@test.com",
1818
maxLength = 100
1919
)
2020
String email,

backend/src/main/java/com/back/api/queue/controller/QueueEntryApi.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ ApiResponse<QueueEntryStatusResponse> getMyQueueEntryStatus(
3232

3333

3434
@Operation(
35-
summary = "대기열 진입 여부 조회",
36-
description = "사용자가 특정 이벤트의 대기열에 진입했는지 조회합니다."
35+
summary = "대기열 입장 완료 여부 조회",
36+
description = "사용자가 특정 이벤트의 대기열에 입장했는지 조회합니다.(ENTERED)"
3737
)
3838
ApiResponse<Boolean> existsInQueue(
3939
@Parameter(description = "이벤트 ID", example = "1")

backend/src/main/java/com/back/api/queue/controller/QueueEntryController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public ApiResponse<Boolean> existsInQueue(
4545
@PathVariable Long eventId
4646
) {
4747
Long userId = httpRequestContext.getUserId();
48-
boolean exists = queueEntryReadService.existsInWaitingQueue(eventId, userId);
49-
return ApiResponse.ok("대기열 진입 여부를 확인했습니다.", exists);
48+
boolean exists = queueEntryReadService.isUserEntered(eventId, userId);
49+
return ApiResponse.ok("대기열 입장 완료 여부를 확인했습니다.(ENTERED)", exists);
5050
}
5151

5252
@Override

backend/src/main/java/com/back/api/queue/scheduler/QueueShuffleScheduler.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class QueueShuffleScheduler {
3636
private final QueueEntryRepository queueEntryRepository;
3737
private final QueueShuffleService queueShuffleService;
3838
private final EventService eventService;
39-
private final PreRegisterRepository preRegisterRepository; //TODO service로 변경 필요
39+
private final PreRegisterRepository preRegisterRepository;
4040
private final QueueSchedulerProperties properties;
4141

4242
@Scheduled(cron = "${queue.scheduler.shuffle.cron}", zone = "Asia/Seoul")
@@ -149,7 +149,6 @@ private boolean shuffleQueueForEvent(Event event) {
149149
return false;
150150
}
151151

152-
//TODO PreRegisterService로 변경 필요
153152
List<Long> preRegisteredUserIds = preRegisterRepository.findRegisteredUserIdsByEventId(eventId);
154153

155154
if (preRegisteredUserIds.isEmpty()) {

backend/src/main/java/com/back/api/queue/service/QueueEntryProcessService.java

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
/*
3636
* 대기열 처리 로직
3737
* QueueEntry 입장 처리
38-
* 스케줄러, 배치 활용
38+
* 스케줄러 활용
3939
* 대기중 -> 입장 완료
4040
*/
4141

@@ -91,22 +91,98 @@ public void processBatchEntry(Long eventId, List<Long> userIds) {
9191
}
9292
}
9393

94-
/* ==================== 이벤트 단위 자동 입장 처리 (스케줄러) ==================== */
94+
/*
95+
Redis에만 의존. Redis + DB 로직으로 수정했으나 주석처리 보관
96+
*/
97+
// @Transactional
98+
// public void processEventQueueEntries(Event event) {
99+
//
100+
// Long eventId = event.getId();
101+
//
102+
// //대기 중인 인원 확인
103+
// Long totalWaitingCount = queueEntryRedisRepository.getTotalWaitingCount(eventId);
104+
//
105+
// if (totalWaitingCount == 0) {
106+
// return;
107+
// }
108+
//
109+
// //입장 완료된 인원 확인
110+
// Long currentEnteredCount = queueEntryRedisRepository.getTotalEnteredCount(eventId);
111+
// int maxEnteredLimit = properties.getEntry().getMaxEnteredLimit();
112+
//
113+
// //입장 가능한 인원 확인
114+
// int availableEnteredCount = maxEnteredLimit - currentEnteredCount.intValue();
115+
//
116+
// if (availableEnteredCount <= 0) {
117+
// log.info("[EventId: {}] 최대 수용 인원 도달 - 현재: {}명, 최대: {}명",
118+
// eventId, currentEnteredCount, maxEnteredLimit);
119+
// return;
120+
// }
121+
//
122+
// //한번에 입장시킬 인원
123+
// int batchSize = properties.getEntry().getBatchSize();
124+
//
125+
// // 입장 인원 선정
126+
// // 빈 자리 순차적으로 들어갈 수 있도록 함
127+
// int entryCount = Math.min(
128+
// batchSize,
129+
// Math.min(availableEnteredCount, totalWaitingCount.intValue()) // 빈 자리와 대기 인원 중 작은 값
130+
// );
131+
//
132+
// log.info("입장 처리 - eventId: {}, 대기: {}명, 입장완료: {}명, 빈자리: {}명, 배치사이즈: {}명, 입장시킬인원: {}명",
133+
// eventId, totalWaitingCount, currentEnteredCount, availableEnteredCount, batchSize, entryCount);
134+
//
135+
//
136+
// //상위 N명 추출
137+
// Set<Object> topWaitingUsers = queueEntryRedisRepository.getTopWaitingUsers(eventId, entryCount);
138+
//
139+
// if (topWaitingUsers.isEmpty()) {
140+
// return;
141+
// }
142+
//
143+
// List<Long> userIds = new ArrayList<>();
144+
// for (Object userId : topWaitingUsers) {
145+
// userIds.add(Long.parseLong(userId.toString()));
146+
// }
147+
//
148+
// processBatchEntry(eventId, userIds); // 입장 순서인 사용자 입장처리
149+
//
150+
// publishWaitingUpdateEvents(eventId); // 대기중인 사용자 실시간 순위 업데이트
151+
//
152+
// }
95153

154+
/* ==================== 이벤트 단위 자동 입장 처리 (스케줄러) ==================== */
155+
// Redis + DB
96156
@Transactional
97157
public void processEventQueueEntries(Event event) {
98158

99159
Long eventId = event.getId();
100160

101161
//대기 중인 인원 확인
102-
Long totalWaitingCount = queueEntryRedisRepository.getTotalWaitingCount(eventId);
162+
Long totalWaitingCount;
163+
164+
try {
165+
totalWaitingCount = queueEntryRedisRepository.getTotalWaitingCount(eventId);
166+
} catch (Exception e) {
167+
log.warn("Redis 조회 실패, DB로부터 대기 중 인원 수 조회 시도 - eventId: {}", eventId, e);
168+
totalWaitingCount = queueEntryRepository.countByEvent_IdAndQueueEntryStatus(eventId, QueueEntryStatus.WAITING);
169+
}
103170

104171
if (totalWaitingCount == 0) {
105172
return;
106173
}
107174

108175
//입장 완료된 인원 확인
109-
Long currentEnteredCount = queueEntryRedisRepository.getTotalEnteredCount(eventId);
176+
Long currentEnteredCount;
177+
178+
try {
179+
currentEnteredCount = queueEntryRedisRepository.getTotalEnteredCount(eventId);
180+
} catch (Exception e) {
181+
log.warn("Redis 조회 실패, DB로부터 입장 완료된 인원 수 조회 시도 - eventId: {}", eventId, e);
182+
currentEnteredCount = queueEntryRepository.countByEvent_IdAndQueueEntryStatus(eventId, QueueEntryStatus.ENTERED);
183+
}
184+
185+
110186
int maxEnteredLimit = properties.getEntry().getMaxEnteredLimit();
111187

112188
//입장 가능한 인원 확인
@@ -132,16 +208,20 @@ public void processEventQueueEntries(Event event) {
132208
eventId, totalWaitingCount, currentEnteredCount, availableEnteredCount, batchSize, entryCount);
133209

134210

135-
//상위 N명 추출
136-
Set<Object> topWaitingUsers = queueEntryRedisRepository.getTopWaitingUsers(eventId, entryCount);
137211

138-
if (topWaitingUsers.isEmpty()) {
139-
return;
212+
List<Long> userIds;
213+
try {
214+
Set<Object> topWaitingUsers = queueEntryRedisRepository.getTopWaitingUsers(eventId, entryCount);
215+
userIds = topWaitingUsers.stream()
216+
.map(obj -> Long.parseLong(obj.toString()))
217+
.toList();
218+
} catch (Exception e) {
219+
log.warn("Redis 조회 실패, DB로부터 상위 대기 인원 조회 시도 - eventId: {}", eventId, e);
220+
userIds = queueEntryRepository.findTopNWaitingUsers(eventId, entryCount);
140221
}
141222

142-
List<Long> userIds = new ArrayList<>();
143-
for (Object userId : topWaitingUsers) {
144-
userIds.add(Long.parseLong(userId.toString()));
223+
if (userIds.isEmpty()) {
224+
return;
145225
}
146226

147227
processBatchEntry(eventId, userIds); // 입장 순서인 사용자 입장처리
@@ -332,7 +412,7 @@ public void expireBatchEntries(List<QueueEntry> entries) {
332412

333413
/* ==================== 결제 완료 처리 ==================== */
334414

335-
//TODO 결제 도메인에서 사용 필요
415+
336416
@Transactional
337417
public void completePayment(Long eventId, Long userId) {
338418

backend/src/main/java/com/back/api/queue/service/QueueEntryReadService.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
/*
2323
* 대기열 조회 로직
2424
* Redis 우선 조회 -> DB 조회
25-
* 트랜잭션 읽기 / 쓰기 분리 고려
2625
* TODO 시간 계산 로직 수정
2726
*/
2827
@Service
@@ -115,8 +114,20 @@ public boolean existsInWaitingQueue(Long eventId, Long userId) {
115114
//Redis & DB
116115
public boolean isUserEntered(Long eventId, Long userId) {
117116
try {
118-
return queueEntryRedisRepository.isInEnteredQueue(eventId, userId);
117+
boolean isInRedis = queueEntryRedisRepository.isInEnteredQueue(eventId, userId);
118+
119+
if (isInRedis) {
120+
return true;
121+
}
122+
123+
//Redis false면 DB 한번 더 확인
124+
return queueEntryRepository
125+
.findByEvent_IdAndUser_Id(eventId, userId)
126+
.map(entry -> entry.getQueueEntryStatus() == QueueEntryStatus.ENTERED)
127+
.orElse(false);
128+
119129
} catch (Exception e) {
130+
// Redis 예외 시 DB 조회
120131
log.warn("Redis ENTERED 조회 실패, DB Fallback");
121132

122133
return queueEntryRepository

backend/src/main/java/com/back/api/queue/service/QueueShuffleService.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ public void shuffleQueue(Long eventId, List<Long> preRegisteredUserIds) {
5959

6060
event.changeStatus(EventStatus.QUEUE_READY);
6161

62-
//TODO 알림 로직 추가 필요
63-
6462
}
6563

6664
private void validateShuffleRequest(Long eventId, List<Long> preRegisteredUserIds) {

backend/src/main/java/com/back/api/user/dto/response/UserProfileResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public record UserProfileResponse(
1313
Long userId,
1414
@Schema(
1515
description = "사용자 이메일",
16-
example = "user@example.com",
16+
example = "test@test.com",
1717
maxLength = 100
1818
)
1919
String email,

0 commit comments

Comments
 (0)