-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Labels
담당: 규일🍊규일 담당 작업규일 담당 작업도메인: 챌린지🏆챌린지 관련 기능 작업챌린지 관련 기능 작업우선순위: P3백로그, 당장 급하지 않은 아이디어 및 기술 부채백로그, 당장 급하지 않은 아이디어 및 기술 부채
Description
문제 설명
현재 챌린지 생성 로직에서 user당 활성 챌린지는 1개만 가능해야 하는 비즈니스 규칙이 있습니다.
현재 구현 상태 ✅
- 애플리케이션 레벨 검증으로 구현 완료
- 위치:
ChallengeService.validateNoDuplicateActiveChallenge() - 정상적인 API 요청에 대해서는 중복 생성 방지 동작
기술 부채 🔶
- DB 레벨 제약이 없어 동시성 문제(Race Condition)에 취약
- 추후 팀 논의를 통해 DB 제약 추가 여부 결정 필요
현재 구현
검증 방식
// ChallengeCreationFacade.java:49-50
challengeService.validateNoDuplicateActiveChallenge(userId);
// ChallengeService.java:28-32
public void validateNoDuplicateActiveChallenge(Long userId) {
if (challengeRepository.existsByUserIdAndIsActiveTrue(userId)) {
throw new ChallengeException(ChallengeErrorCode.DUPLICATE_ACTIVE_CHALLENGE);
}
}
잠재적 문제: Race Condition
동시에 2개의 챌린지 생성 요청이 들어올 경우:
Time Request A Request B
---- --------- ---------
T1 existsByUserId(1) → false
T2 existsByUserId(1) → false
T3 save(Challenge) ✓
T4 save(Challenge) ✓
결과: User 1에게 활성 챌린지 2개 생성됨 ❌
발생 확률:
- 일반적인 사용: 매우 낮음 (사용자가 동시에 2번 클릭할 가능성)
- 악의적 공격: 높음 (동시 요청 의도적으로 발생 시)
해결 방안 (추후 논의 필요)
Option 1: DB Unique Partial Index
장점:
- 데이터 무결성 강력 보장 (모든 경로에서)
- 성능 우수 (인덱스 검색 O(log n))
- 비활성 챌린지는 여러 개 가능
구현:
CREATE UNIQUE INDEX CONCURRENTLY idx_user_active_challenge
ON challenges(user_id) WHERE is_active = true;
단점:
- SQL 스크립트 수동 실행 필요 (또는 Flyway 도입)
난이도: ⭐️ (낮음)
---
Option 2: Flyway 마이그레이션 도구 도입
장점:
- 스키마 변경 자동화
- 버전 관리 및 팀 협업 용이
- 프로덕션 배포 안전
- DB Unique Index와 함께 사용
단점:
- 추가 의존성 필요
- 초기 설정 및 학습 필요
- 로컬 개발 환경 구성 변경
난이도: ⭐️⭐️⭐️ (중간)
---
Option 3: 애플리케이션 레벨 락
장점:
- 추가 의존성 없음
- 코드만으로 해결
단점:
- DB 제약 없어 데이터 정합성 약함
- 성능 영향 (비관적 락: row lock, 낙관적 락: 재시도)
- 직접 DB 접근 시 보호 안 됨
- 복잡도 증가
난이도: ⭐️⭐️ (낮음-중간)
---
Option 4: 현상 유지 (기술 부채 수용)
장점:
- 추가 작업 불필요
- 현재 동작 유지
단점:
- 동시성 이슈 발생 가능성 존재
- 추후 문제 발생 시 데이터 정리 필요
비교표
| 항목 | 현재 상태 | +DB Index | +Flyway | +락 |
|---------------|-----------|--------------|-------------|-----------|
| 데이터 무결성 | ⚠️ 약함 | ✅ 강함 | ✅ 강함 | ⚠️ 약함 |
| 성능 | ✅ 빠름 | ✅ 빠름 | ✅ 빠름 | ❌ 느림 |
| 복잡도 | ✅ 낮음 | ✅ 낮음 | ⚠️ 보통 | ❌ 높음 |
| 자동화 | ✅ 자동 | ❌ 수동 | ✅ 자동 | ✅ 자동 |
| 추가 작업 | - | SQL 1회 실행 | 의존성 추가 | 코드 수정 |
참고 자료
관련 파일:
- ChallengeCreationFacade.java:49-50 - 검증 호출
- ChallengeService.java:28-32 - 검증 로직
- ChallengeRepository.java:17 - 존재 여부 확인 쿼리
- Challenge.java:43-44 - isActive 필드
작성된 SQL 스크립트 (필요시 사용):
- src/main/resources/db/20260105_add_unique_active_challenge_constraint.sql
팀 논의 필요 사항
1. 우선순위 결정
- 동시성 이슈의 비즈니스 영향도는?
- 언제까지 해결해야 하는가?
2. 해결 방안 선택
- DB Index만 추가? (빠른 해결)
- Flyway 도입? (장기적 이득, 초기 비용)
- 현상 유지? (기술 부채 수용)
3. 개발 환경 전략
- 로컬 vs 배포 환경 스키마 관리 방법
- 팀원 간 DB 동기화 방법
4. 마이그레이션 계획
- 기존 중복 데이터 확인 및 정리
- 배포 일정 및 롤백 계획
제안
단계적 접근:
1. 1단계 (즉시): 현재 애플리케이션 레벨 검증 유지 ✅ 완료
2. 2단계 (논의 후): DB Unique Index 추가 (SQL 스크립트 준비됨)
3. 3단계 (선택): Flyway 도입 검토 (팀 역량 및 필요성에 따라)Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
담당: 규일🍊규일 담당 작업규일 담당 작업도메인: 챌린지🏆챌린지 관련 기능 작업챌린지 관련 기능 작업우선순위: P3백로그, 당장 급하지 않은 아이디어 및 기술 부채백로그, 당장 급하지 않은 아이디어 및 기술 부채