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

Redis 트랜잭션 대신 Redisson 분산락을 활용하여 재고 감소 로직 구현 #135

Conversation

daadaadaah
Copy link
Collaborator

@daadaadaah daadaadaah commented Jul 11, 2023

Why

  • 다음 작업을 묶어서 처리해야 됩니다. 즉, 1번째 명령어 실행 결과에 따라 2번째 명령어 실행 여부가 결정이 되는데,
int inventoryAfterDecrease = inventoryCommandRepository.decreaseByAmount(dealProductUuid, orderQuantity); // 1번째 명령어

int inventoryBeforeDecrease = orderQuantity + inventoryAfterDecrease;

if (inventoryBeforeDecrease > 0 && inventoryBeforeDecrease < orderQuantity && outOfStockHandlingOption == OutOfStockHandlingOption.PARTIAL_ORDER) {
    inventoryCommandRepository.set(dealProductUuid, 0); // 2번째 명령어
}
  • 이를 트랜잭션으로 처리하게 되면, 제가 의도한 대로 1번째 명령어 실행 결과에 따라 2번째 명령어 실행 여부가 결정을 할 수 없습니다.
  • 왜냐하면, Redis의 트랜잭션은 1번째 명령어와 2번째 명령어를 queue에 담겨 배치 처리되기 떄문입니다.
private int[] decreaseInventoryInAdvance(UUID dealProductUuid, int orderQuantity, OutOfStockHandlingOption outOfStockHandlingOption) {
        final int[] inventoryAfterDecrease = new int[1];

        redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations operations) throws DataAccessException {
                try {
                    operations.multi();

                    inventoryAfterDecrease[0] = inventoryCommandRepository.decreaseByAmount(dealProductUuid, orderQuantity); // 1번째 명령어

                    int inventoryBeforeDecrease = orderQuantity + inventoryAfterDecrease[0];

                    if (inventoryBeforeDecrease < orderQuantity && outOfStockHandlingOption == OutOfStockHandlingOption.PARTIAL_ORDER) {
                        inventoryCommandRepository.set(dealProductUuid, 0);  // 2번째 명령어
                    }

                    return operations.exec(); 
                } catch (Exception e) {
                    operations.discard();
                    throw e;
                }
            }
        });

        return inventoryAfterDecrease;
    }
  • 그래서, 여러 명령어를 원자성 있게 처리하는 동시에 명령어들이 배치로 처리되지 않고 개별 처리 될 수 있는 분산락을 사용했습니다.

Comment

@daadaadaah daadaadaah changed the title Redis 트랜잭션 대신 Redisson 분산락을 활용하여 재고 감소 로직 구현 [WIP] Redis 트랜잭션 대신 Redisson 분산락을 활용하여 재고 감소 로직 구현 Jul 11, 2023
@daadaadaah daadaadaah force-pushed the fix/change-redis-transaction-to-distribution-lock branch from dc3f7dd to daa5721 Compare July 13, 2023 11:33
@daadaadaah daadaadaah requested a review from f-lab-TJ July 13, 2023 11:34
@daadaadaah daadaadaah changed the title [WIP] Redis 트랜잭션 대신 Redisson 분산락을 활용하여 재고 감소 로직 구현 Redis 트랜잭션 대신 Redisson 분산락을 활용하여 재고 감소 로직 구현 Jul 13, 2023
@daadaadaah daadaadaah merged commit d855479 into f-lab-edu:develop Jul 13, 2023
1 check failed
log.info("[lock 획득] userId = {}, dealProductUuid ={}, orderQuantity ={}", userId, dealProductUuid, orderQuantity);

try {
int inventoryAfterDecrease = inventoryCommandRepository.decreaseByAmount(dealProductUuid, orderQuantity);

Choose a reason for hiding this comment

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

인벤토리 재고를 get해서 미리 확인하지 않는 이유가 있을까요? 재고가 0이 되어 있는 경우에는 decrease를 하면 안될것 같네요.

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