문제점
- 문제점: 링크
short_id
컬럼은 unique column인데, 동일한 short_id
값을 가진 데이터가 동시에 DB에 insert될 경우 데이터베이스에서는 중복오류가 발생할 것이다. (jpa의 경우 DataIntegrityViolationException
)
@Service
@Transactional
@RequiredArgsConstructor
public class ShortLinkService {
private final ShortLinkRepository shortLinkRepository;
public ShortLinkEntity createShortLink(String url, String clientIp, String userAgent) {
String randomShortId = createRandomShortId();
ShortLinkEntity newShortLinkEntity = ShortLinkEntity.createShortUrlEntity(url, randomShortId, clientIp, userAgent);
return shortLinkRepository.save(newShortLinkEntity);
}
}
- 즉,
shortLinkRepository.save(newShortLinkEntity);
이 부분에서 에러가 터질 수 있다.
해결방안
- 정해진 해결방안은 없는 것 같다.
- 클라이언트보고 다시 요청하라고 하던가, 백엔드에서 처리를 해야한다.
- 메시지 큐를 이용하던가, 새로운 ShortId로 DB로 Retry를 해야한다.
- 본문에서는 Retry를 하는 방식으로 문제를 해결하려고 한다.
- 예외 처리를 5번 반복으로 설정했다. 5번 정도면 거의 불가능한 확률이다.
public ShortLinkEntity createShortLink(String url, String clientIp, String userAgent) {
for (int i = 0; i < 5; i++) {
String randomShortId = createRandomShortId();
ShortLinkEntity newShortLinkEntity = ShortLinkEntity.createShortUrlEntity(url, randomShortId, clientIp, userAgent);
Exception exceptionHolder = null;
try {
return shortLinkRepository.save(newShortLinkEntity);
} catch (Exception e) {
exceptionHolder = e;
}
}
throw new Custom5xxException(EXHAUSTED_SHORT_LINK);
}
- 이러한 로직이 반복될 경우, AOP로 로직을 빼버려도 될듯하다.