-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(#100): 카프카에서 사용하는 토픽들을 관리하는 문자열 상수 클래스를 commons에 정의 * feat(#22): Dto 모듈에 OrderDto 생성 * chore(#100): 카프카 설정 및 PreOrderProducer 등록 - 카프카 의존성 및 설정 - 오더서버로 사전예약상품 정보를 전송하는 카프카 빈 추가 * rename(#100): ProductSearchDto를 utils 패키지로 이동 * feat(#100): 사전예약주문 API 구현 - Redission 으로 분산락 구현 - validate로 사전예약주문기간, 중복여부, 사전예약수량 여부 확인 --------- Co-authored-by: linavell <linavell@naver.com>
- Loading branch information
Showing
25 changed files
with
368 additions
and
22 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
common/domain/src/main/java/com/sparta/common/domain/entity/KafkaTopicConstant.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,7 @@ | ||
package com.sparta.common.domain.entity; | ||
|
||
public class KafkaTopicConstant { | ||
public static final String PROCESS_PREORDER = "process_preorder"; | ||
public static final String ERROR_IN_PROCESS_PREORDER = "error_in_create_delivery"; | ||
public static final String PAYMENT_COMPLETED = "payment-completed-topic"; | ||
} |
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
36 changes: 36 additions & 0 deletions
36
...erver/src/main/java/com/sparta/product/application/preorder/DistributedLockComponent.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,36 @@ | ||
package com.sparta.product.application.preorder; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.aspectj.lang.annotation.Aspect; | ||
import org.redisson.api.RLock; | ||
import org.redisson.api.RedissonClient; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Aspect | ||
@Component | ||
@RequiredArgsConstructor | ||
@Slf4j(topic = "DistributedLockComponent") | ||
public class DistributedLockComponent { | ||
private final RedissonClient redissonClient; | ||
|
||
public void execute( | ||
String lockName, long waitMilliSecond, long leaseMilliSecond, Runnable logic) { | ||
RLock lock = redissonClient.getLock(lockName); | ||
try { | ||
boolean isLocked = lock.tryLock(waitMilliSecond, leaseMilliSecond, TimeUnit.MILLISECONDS); | ||
if (!isLocked) { | ||
throw new IllegalStateException("[" + lockName + "] lock 획득 실패"); | ||
} | ||
logic.run(); | ||
} catch (InterruptedException e) { | ||
log.error(e.getMessage(), e); | ||
throw new RuntimeException(e); | ||
} finally { | ||
if (lock.isHeldByCurrentThread()) { | ||
lock.unlock(); | ||
} | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
...ct/server/src/main/java/com/sparta/product/application/preorder/PreOrderCacheService.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,19 @@ | ||
package com.sparta.product.application.preorder; | ||
|
||
import com.sparta.product.domain.model.PreOrder; | ||
import com.sparta.product.infrastructure.utils.PreOrderRedisDto; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.cache.annotation.Cacheable; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class PreOrderCacheService { | ||
private final PreOrderService preOrderService; | ||
|
||
@Cacheable(cacheNames = "preOrder", key = "#preOrderId") | ||
public PreOrderRedisDto getPreOrderCache(Long preOrderId) { | ||
PreOrder preOrder = preOrderService.findPreOrderByPreOrderId(preOrderId); | ||
return new PreOrderRedisDto(preOrder); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
...t/server/src/main/java/com/sparta/product/application/preorder/PreOrderFacadeService.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,39 @@ | ||
package com.sparta.product.application.preorder; | ||
|
||
import com.sparta.common.domain.entity.KafkaTopicConstant; | ||
import com.sparta.product.domain.model.PreOrder; | ||
import com.sparta.product.domain.model.PreOrderState; | ||
import com.sparta.product.infrastructure.messaging.PreOrderProducer; | ||
import com.sparta.product.presentation.exception.ProductErrorCode; | ||
import com.sparta.product.presentation.exception.ProductServerException; | ||
import dto.OrderDto.OrderCreateRequest; | ||
import java.time.LocalDateTime; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class PreOrderFacadeService { | ||
private final PreOrderService preOrderService; | ||
private final PreOrderProducer preOrderProducer; | ||
private final PreOrderLockService preOrderLockService; | ||
|
||
@Transactional | ||
public void preOrder(Long preOrderId, Long addressId, Long userId) { | ||
PreOrder preOrder = preOrderService.findPreOrderByPreOrderId(preOrderId); | ||
preOrderLockService.reservation(preOrderId, userId); | ||
OrderCreateRequest createRequest = PreOrderMapper.toDto(preOrderId, addressId); | ||
preOrderProducer.send(KafkaTopicConstant.PROCESS_PREORDER, preOrderId, createRequest); | ||
} | ||
|
||
private void validatePreOrder(PreOrder preOrder) { | ||
if (preOrder.getState() != PreOrderState.OPEN_FOR_ORDER) | ||
throw new ProductServerException(ProductErrorCode.NOT_OPEN_FOR_PREORDER); | ||
|
||
LocalDateTime now = LocalDateTime.now(); | ||
if (now.isBefore(preOrder.getStartDateTime()) || now.isAfter(preOrder.getEndDateTime())) { | ||
throw new ProductServerException(ProductErrorCode.CLOSED_PREORDER); | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
...uct/server/src/main/java/com/sparta/product/application/preorder/PreOrderLockService.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,28 @@ | ||
package com.sparta.product.application.preorder; | ||
|
||
import static com.sparta.product.infrastructure.utils.RedisUtils.getRedisKeyOfPreOrder; | ||
|
||
import com.sparta.product.infrastructure.utils.PreOrderRedisDto; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class PreOrderLockService { | ||
private final PreOrderRedisService redisService; | ||
private final PreOrderCacheService cacheService; | ||
private final DistributedLockComponent lockComponent; | ||
|
||
public void reservation(long preOrderId, long userId) { | ||
PreOrderRedisDto cachedPreOrder = cacheService.getPreOrderCache(preOrderId); | ||
cachedPreOrder.validateReservationDate(); // 사전예약기간인지 검증 | ||
lockComponent.execute( // 락을 걸고 | ||
"preOrderLock_%s".formatted(preOrderId), | ||
3000, | ||
3000, | ||
() -> { | ||
redisService.validateQuantity(cachedPreOrder, userId); // 이미 예약에 성공한 유저인지, 수량안에 든 유저인지 검증 | ||
}); | ||
redisService.preOrder(getRedisKeyOfPreOrder(preOrderId), userId); | ||
} | ||
} |
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
37 changes: 37 additions & 0 deletions
37
...ct/server/src/main/java/com/sparta/product/application/preorder/PreOrderRedisService.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,37 @@ | ||
package com.sparta.product.application.preorder; | ||
|
||
import static com.sparta.product.infrastructure.utils.RedisUtils.getRedisKeyOfPreOrder; | ||
|
||
import com.sparta.product.domain.repository.redis.RedisRepository; | ||
import com.sparta.product.infrastructure.utils.PreOrderRedisDto; | ||
import com.sparta.product.presentation.exception.ProductErrorCode; | ||
import com.sparta.product.presentation.exception.ProductServerException; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class PreOrderRedisService { | ||
private final RedisRepository redisRepository; | ||
|
||
public void validateQuantity(PreOrderRedisDto cache, long userId) { | ||
if (!availableUser(cache.preOrderId(), userId)) | ||
throw new ProductServerException(ProductErrorCode.ALREADY_PREORDER); | ||
if (!availableQuantity(cache.availableQuantity(), cache.preOrderId())) | ||
throw new ProductServerException(ProductErrorCode.EXCEED_PREORDER_QUANTITY); | ||
} | ||
|
||
public void preOrder(String key, long userId) { | ||
redisRepository.sAdd(key, Long.toString(userId)); | ||
} | ||
|
||
public boolean availableUser(long preOrderId, long userId) { // 중복 요청 확인 | ||
String key = getRedisKeyOfPreOrder(preOrderId); | ||
return !redisRepository.sIsMember(key, String.valueOf(userId)); | ||
} | ||
|
||
public boolean availableQuantity(int availableQuantity, long preOrderId) { // 수량 검증 | ||
String key = getRedisKeyOfPreOrder(preOrderId); | ||
return availableQuantity > redisRepository.sCard(key); | ||
} | ||
} |
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
2 changes: 1 addition & 1 deletion
2
...ct/server/src/main/java/com/sparta/product/domain/repository/ElasticSearchRepository.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
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
23 changes: 23 additions & 0 deletions
23
...duct/server/src/main/java/com/sparta/product/domain/repository/redis/RedisRepository.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,23 @@ | ||
package com.sparta.product.domain.repository.redis; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class RedisRepository { | ||
private final RedisTemplate<String, String> redisTemplate; | ||
|
||
public Long sAdd(String key, String value) { | ||
return redisTemplate.opsForSet().add(key, value); | ||
} | ||
|
||
public Long sCard(String key) { | ||
return redisTemplate.opsForSet().size(key); | ||
} | ||
|
||
public Boolean sIsMember(String key, String value) { | ||
return redisTemplate.opsForSet().isMember(key, value); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
...uct/server/src/main/java/com/sparta/product/infrastructure/configuration/KafkaConfig.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,20 @@ | ||
package com.sparta.product.infrastructure.configuration; | ||
|
||
import com.sparta.product.infrastructure.messaging.PreOrderProducer; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.kafka.core.KafkaTemplate; | ||
|
||
@ConditionalOnProperty(value = "kafka.enabled", matchIfMissing = true) | ||
@RequiredArgsConstructor | ||
@Configuration | ||
public class KafkaConfig { | ||
private final KafkaTemplate<String, Object> kafkaTemplate; | ||
|
||
@Bean | ||
public PreOrderProducer preOrderProducer() { | ||
return new PreOrderProducer(kafkaTemplate); | ||
} | ||
} |
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
26 changes: 26 additions & 0 deletions
26
.../server/src/main/java/com/sparta/product/infrastructure/configuration/RedissonConfig.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,26 @@ | ||
package com.sparta.product.infrastructure.configuration; | ||
|
||
import org.redisson.Redisson; | ||
import org.redisson.api.RedissonClient; | ||
import org.redisson.config.Config; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class RedissonConfig { | ||
private static final String REDIS_URL_PREFIX = "redis://"; | ||
|
||
@Value("${spring.data.redis.host}") | ||
private String host; | ||
|
||
@Value("${spring.data.redis.port}") | ||
private int port; | ||
|
||
@Bean | ||
RedissonClient redissonClient() { | ||
Config config = new Config(); | ||
config.useSingleServer().setAddress(REDIS_URL_PREFIX + host + ":" + port); | ||
return Redisson.create(config); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...ct/server/src/main/java/com/sparta/product/infrastructure/messaging/PreOrderProducer.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,17 @@ | ||
package com.sparta.product.infrastructure.messaging; | ||
|
||
import dto.OrderDto.OrderCreateRequest; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.kafka.core.KafkaTemplate; | ||
|
||
@RequiredArgsConstructor | ||
@Slf4j(topic = "PreOrderProducer in Product server") | ||
public class PreOrderProducer { | ||
private final KafkaTemplate<String, Object> kafkaTemplate; | ||
|
||
public void send(String topic, Long preOrderId, OrderCreateRequest request) { | ||
kafkaTemplate.send(topic, preOrderId.toString(), request); | ||
log.info("send preorderRequest of {} to order server", preOrderId); | ||
} | ||
} |
Oops, something went wrong.