-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: redisson client 의존성 추가 * feat: 득점자 테이블 요청 순서 추가 * feat: 분산락을 통한 정답 제출 로직 구현 * refactor: 재채점으로 인한 득점자 변경 시 분산락 활용 * feat: 득점자 확인용 캐시 저장소 제거
- Loading branch information
Showing
7 changed files
with
124 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 0 additions & 58 deletions
58
src/main/java/org/cotato/csquiz/domain/education/cache/ScorerExistRedisRepository.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
src/main/java/org/cotato/csquiz/domain/education/facade/RedissonScorerFacade.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.cotato.csquiz.domain.education.facade; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.cotato.csquiz.common.error.ErrorCode; | ||
import org.cotato.csquiz.common.error.exception.AppException; | ||
import org.cotato.csquiz.domain.education.entity.Quiz; | ||
import org.cotato.csquiz.domain.education.entity.Record; | ||
import org.cotato.csquiz.domain.education.service.ScorerService; | ||
import org.redisson.api.RLock; | ||
import org.redisson.api.RedissonClient; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class RedissonScorerFacade { | ||
|
||
private static final String KEY_PREFIX = "$Scorer_lock_"; | ||
private final ScorerService scorerService; | ||
private final RedissonClient redissonClient; | ||
|
||
public void checkAndThenUpdateScorer(Record memberReply) { | ||
RLock lock = redissonClient.getLock(generateKey(memberReply.getQuiz())); | ||
|
||
try { | ||
boolean available = lock.tryLock(30, 1, TimeUnit.SECONDS); | ||
|
||
if (!available) { | ||
log.error("[락 획득 실패 (Record : {})]", memberReply.getId()); | ||
throw new AppException(ErrorCode.SCORER_LOCK_ERROR); | ||
} | ||
scorerService.checkAndThenUpdateScorer(memberReply); | ||
|
||
} catch (InterruptedException e) { | ||
throw new AppException(ErrorCode.SCORER_LOCK_ERROR); | ||
} finally { | ||
if (lock.isLocked() && lock.isHeldByCurrentThread()) { | ||
lock.unlock(); | ||
} | ||
} | ||
} | ||
|
||
private String generateKey(final Quiz quiz) { | ||
return KEY_PREFIX + quiz.getId(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
src/main/java/org/cotato/csquiz/domain/education/service/ScorerService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.cotato.csquiz.domain.education.service; | ||
|
||
import java.util.Optional; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.cotato.csquiz.domain.education.entity.Quiz; | ||
import org.cotato.csquiz.domain.education.entity.Record; | ||
import org.cotato.csquiz.domain.education.entity.Scorer; | ||
import org.cotato.csquiz.domain.education.repository.ScorerRepository; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Propagation; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class ScorerService { | ||
|
||
private final ScorerRepository scorerRepository; | ||
|
||
@Transactional(propagation = Propagation.REQUIRES_NEW) | ||
public void checkAndThenUpdateScorer(Record memberReply) { | ||
Optional<Scorer> maybeScorer = scorerRepository.findByQuizId(memberReply.getQuiz().getId()); | ||
|
||
maybeScorer.ifPresentOrElse( | ||
scorer -> { | ||
if (scorer.getTicketNumber() > memberReply.getTicketNumber()) { | ||
scorer.updateScorer(memberReply.getMemberId(), memberReply.getTicketNumber()); | ||
scorerRepository.save(scorer); | ||
log.info("득점자 업데이트 : 티켓번호: {}", memberReply.getTicketNumber()); | ||
} | ||
}, | ||
() -> { | ||
createScorer(memberReply.getMemberId(), memberReply.getQuiz(), memberReply.getTicketNumber()); | ||
log.info("득점자 생성 : {}, 티켓번호: {}", memberReply.getMemberId(), memberReply.getTicketNumber()); | ||
} | ||
|
||
); | ||
} | ||
|
||
@Transactional | ||
public void createScorer(final Long memberId, final Quiz quiz, final Long ticketNumber){ | ||
scorerRepository.save(Scorer.of(memberId, quiz, ticketNumber)); | ||
} | ||
} |