Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InventoryCommandRepository 추가 #56

Merged

Conversation

daadaadaah
Copy link
Collaborator

@daadaadaah daadaadaah commented Jun 12, 2023

@daadaadaah daadaadaah changed the title InventoryCommandRepository 추가 [WIP] InventoryCommandRepository 추가 Jun 12, 2023
- Redisson의 분산락을 이용해서 다중 서버 환경에서 데이터 일관성 보장
@daadaadaah daadaadaah force-pushed the feat/add-InventoryCommandRepository branch from a789aae to 45cd97f Compare June 16, 2023 13:40
Comment on lines 69 to 103
@Nested
@DisplayName("with multi thread")
class Context_With_Multi_Thread {

@Test
@DisplayName("does not decrease inventory by amount")
void It_Does_Not_Decrease_Inventory_By_Amount() throws InterruptedException {
int threadCount = 100;

int decreaseAmount = 1;

ExecutorService executorService = Executors.newFixedThreadPool(32);

CountDownLatch latch = new CountDownLatch(threadCount);

for (int i = 0; i < threadCount; i++) {
executorService.submit(() -> {
try {
// Perform the test
inventoryCommandRepository.decreaseByAmountWithoutLock(key, decreaseAmount);
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
latch.countDown();
}
});
}

latch.await();

String value = redisStringsRepository.get(key);

assertNotEquals(0, Integer.valueOf(value));
}
}
Copy link
Collaborator Author

@daadaadaah daadaadaah Jun 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 테스트는 멀티스레드 환경에서 lock이 없을 때에 대한 테스트로, 데이터 정합성이 맞지 않아야 하는데, lock을 했을 때와 동일하게 데이터 정합성이 맞습니다. 😭 그래서, 테스트가 통과하지 않고 있습니다. 왜 lock을 사용했을 때와 사용하지 않았을 때 동일한 결과가 나오는 걸까요? 왜 이런 현상이 발생하는지에 대해 알아보고 싶은데, 어떤 키워드로 알아보는게 좋을까요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두가지 상황이 있을 수 있겠지요.

  1. 우연히/해당 테스트 케이스에 의해 consistency가 계속 보장된 경우
  • 로그를 찍어서 정말 해당 함수들이 원하는 sequence대로 동작하는지 확인해볼 수 있을 것 같습니다.
  • 로직에 wait time을 랜덤하게 넣는것도 가능하겠죠.
  1. 해당 로직이 consistency가 보장된 경우
  • redisTemplate의 decrement가 어떻게 동작하는지 정확하게 알아보면 좋을 것 같습니다.

저는 API 형태를 보았을 때 후자의 케이스로 보이는데, 다시 확인해보시면 좋을 것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

placeOrder 로직을 분산락이 필요 없게 로직 수정해서 이제 테스트가 필요없지만, 공부는 해보겠습니다! 조언 감사합니다😆

@daadaadaah daadaadaah changed the title [WIP] InventoryCommandRepository 추가 InventoryCommandRepository 추가 Jun 16, 2023
import org.springframework.stereotype.Repository;

@Repository
public class InventoryCommandRepository {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InventoryCommandRepository와 InventoryQueryRepository를 따로 나눈 이유는 뭘까요?

Copy link
Collaborator Author

@daadaadaah daadaadaah Jun 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다른 도메인 처럼 쓰기와 읽기 책임을 나눔으로써 단일 책임 원칙을 준수하고 싶었고, 다른 도메인과 일관성을 맞추고 싶어서 따로 나눴습니다.
현재 기획에서 재고라는 도메인이 조회 / 추가, 증가, 감소, 삭제만 있지만, 추후에 타임딜 상품들 재고 조회, 전체 상품 재고 조회 등 조회 뿐만 아니라 추가/삭제도 다양한 방식의 추가 등 다양한 요구사항이 발생할 수 있을 거라고 생각해서, 확장성을 고려해 관심사 분리를 하면, 유지보수가 더 쉽지 않을까 생각했습니다.

return;
}

redisStringsRepository.decreaseByAmount(key, Long.valueOf(amount));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

값이 0 미만이 되는 경우도 발생할 수 있고, 그래도 상관없는걸까요? 예외 처리를 외부 로직에서 해주기도 하지만, 특정 코너케이스들은 해당 함수내에서도 다시 처리를 해주는 것이 해당 함수의 독립성을 보장하기 좋습니다. (이 함수를 차후 다른 곳에서 사용한다면 외부 로직에서 처리했던 예외들은 적용되지 않기 때문)

boolean available = rlock.tryLock(waitTimeForAcquiringLock, leaseTimeForLock, TimeUnit.SECONDS);

if (!available) {
System.out.println("lock 획득 실패 "); // TODO : logger 의논 후 수정하기

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

재시도 로직은 어디에 넣고, 어떤 경우에 재시도 할 수 있도록 할 계획인가요?

redisStringsRepository.decreaseByAmount(key, Long.valueOf(amount));

} catch (InterruptedException e) {
throw new RuntimeException(e); // TODO : 예외 처리 어떻게 할까?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외를 다른 일반적인 예외로 감싸 그냥 던지는 것은 지양해야되는 코드 패턴입니다.
로그를 적고 해당 예외를 그대로 던지거나, 다른 기준에 의해 카테고리화 된 예외를 던져보면 좋을 것 같습니다.

Comment on lines 69 to 103
@Nested
@DisplayName("with multi thread")
class Context_With_Multi_Thread {

@Test
@DisplayName("does not decrease inventory by amount")
void It_Does_Not_Decrease_Inventory_By_Amount() throws InterruptedException {
int threadCount = 100;

int decreaseAmount = 1;

ExecutorService executorService = Executors.newFixedThreadPool(32);

CountDownLatch latch = new CountDownLatch(threadCount);

for (int i = 0; i < threadCount; i++) {
executorService.submit(() -> {
try {
// Perform the test
inventoryCommandRepository.decreaseByAmountWithoutLock(key, decreaseAmount);
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
latch.countDown();
}
});
}

latch.await();

String value = redisStringsRepository.get(key);

assertNotEquals(0, Integer.valueOf(value));
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두가지 상황이 있을 수 있겠지요.

  1. 우연히/해당 테스트 케이스에 의해 consistency가 계속 보장된 경우
  • 로그를 찍어서 정말 해당 함수들이 원하는 sequence대로 동작하는지 확인해볼 수 있을 것 같습니다.
  • 로직에 wait time을 랜덤하게 넣는것도 가능하겠죠.
  1. 해당 로직이 consistency가 보장된 경우
  • redisTemplate의 decrement가 어떻게 동작하는지 정확하게 알아보면 좋을 것 같습니다.

저는 API 형태를 보았을 때 후자의 케이스로 보이는데, 다시 확인해보시면 좋을 것 같습니다.

@daadaadaah daadaadaah force-pushed the feat/add-InventoryCommandRepository branch from 5c5e5a7 to 4a43f0c Compare June 25, 2023 05:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants