Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
## 🛠️ 작업 내용
## 🚀 작업 개요
-

## 🛠️ 작업 내용
-

## ✅ PR 유형
- [ ] 버그 수정
- [ ] 성능 개선
- [x] 새로운 기능 추가
- [x] CSS 등 사용자 UI 디자인 변경
- [x] 코드 리팩토링
- [x] 파일 혹은 폴더명 수정
- [ ] 문서 수정
- [ ] 설정 변경

## ✅ Check List
- [x] 코드가 정상적으로 컴파일되나요?
Expand All @@ -14,6 +20,6 @@
- [x] Label을 지정했나요?

## 🔗 관련 이슈
-


## 💬 기타 참고 사항
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ public Object execute(org.springframework.data.redis.core.RedisOperations operat
}
}
} finally {
// 작업 완료 후 각 레슨별로 이번 배치에서 처리한 개수만큼 Busy 카운터 감소
// 작업 완료 후 각 레슨별로 마지막 처리 시점 기록
// 작업 완료 후 각 레슨별로 이번 배치에서 처리한 개수만큼 Busy 카운터 감소, 마지막 처리 시점 기록
Map<Long, Long> countsPerLesson = messages.stream()
.collect(Collectors.groupingBy(ApplyMessage::lessonId, Collectors.counting()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ public class LessonStockReconciliationScheduler {
@Scheduled(fixedRate = 30000)
@SchedulerLock(name = "LessonStockReconciliation", lockAtMostFor = "25s", lockAtLeastFor = "20s")
public void reconcileStock() {
// 대기열 잔여 메세지 존재 시 연기 (Core Redis)
if (hasWaitingRoomMessages()) {
log.info("Waiting room still has messages. Postponing reconciliation.");
return;
}

// 미처리 메세지 존재 시 연기 (MQ Redis)
if (hasStreamLag()) {
log.info("Stream still has pending messages or backlog in MQ. Postponing reconciliation.");
Expand Down Expand Up @@ -75,7 +81,7 @@ public void reconcileStock() {

// 일정 시간 무응답시 교착상태 방지
boolean isStale = (lastActiveStr != null && (now - Long.parseLong(lastActiveStr) > 600000)); // 10분 이상 무응답
boolean isRecent = (lastActiveStr != null && (now - Long.parseLong(lastActiveStr) < 5000)); // 5초 이내 활동
boolean isRecent = (lastActiveStr != null && (now - Long.parseLong(lastActiveStr) < 30000)); // 30초 이내 활동
boolean isNegative = busyCount < 0;

// busy 카운터 존재 & 응답 10분 미만
Expand All @@ -85,7 +91,7 @@ public void reconcileStock() {
continue;
}

// busy 카운터 = 0 & 5초 내 활동이 있었음 (DB트랜잭션 잠시 대기)
// busy 카운터 = 0 & 30초 내 활동이 있었음 (DB트랜잭션 잠시 대기)
if (busyCount == 0 && isRecent) {
log.info("Lesson [{}] recently active. Waiting for safety margin.", lessonId);
continue;
Expand Down Expand Up @@ -134,6 +140,37 @@ public void reconcileStock() {
log.info("Finished Smart Stock Reconciliation for {} lessons.", processedCount);
}

// 미처리 메세지 확인 메서드 (Core Redis)
private boolean hasWaitingRoomMessages() {
String dirtySetKey = LessonApplyStreamConstant.DIRTY_SET_KEY;

// Dirty Set 확인 (Core Redis)
java.util.Set<String> lessonIds = coreRedisTemplate.opsForSet().members(dirtySetKey);
if (lessonIds == null || lessonIds.isEmpty()) {
return false;
}

for (String lessonIdStr : lessonIds) {
try {
Long lessonId = Long.valueOf(lessonIdStr);

// 레슨별 대기열 잔여 메세지 확인 (Core Redis)
String waitingRoomKey = String.format(LessonApplyStreamConstant.WAITING_ROOM_KEY, lessonId);
Long size = coreRedisTemplate.opsForZSet().size(waitingRoomKey);
if (size != null && size > 0) {
log.info("Waiting room still has messages. lessonId={}, size={}", lessonId, size);
return true;
}
} catch (Exception e) {
// 대기열 확인 실패 시 보수적으로 보정 연기
log.warn("Failed to check waiting room for lesson [{}]: {}", lessonIdStr, e.getMessage());
return true;
}
}

return false;
}

// 미처리 메세지 확인 메서드 (MQ Redis)
private boolean hasStreamLag() {
try {
Expand All @@ -151,8 +188,9 @@ private boolean hasStreamLag() {
return size != null && size > 0;

} catch (Exception e) {
// 스트림이 없거나 초기 상태일 경우
return false;
// 스트림 상태 확인 실패 시 보수적으로 보정 연기
log.warn("Failed to check stream lag. Postponing reconciliation: {}", e.getMessage());
return true;
}
}
}
Loading