-
동시성이 터졌다.스파르타 심화/MSA 개인프로젝트 2024. 12. 14. 16:10
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.sparta.msa_exam.order.entity.Order#2]
아주 멋진 에러가 터졌다.
another transaction 바로 동시성 문제
바로 낙관적 락을 걸어주었다.
jpa: properties: hibernate: use_version_always: true 엔티티엔 @Version 추가
Detached entity with generated id '2' has an uninitialized version value 'null': com.sparta.msa_exam.order.entity.Order.version
뭐라는거야 왜 못가져오는데
그냥 flush를 명시적으로 해주었다.
entityManager.persist(order); orderRepository.save(order); orderRepository.flush();
이젠 그냥 막 NPE 에러가 뜬다
Cannot invoke "java.util.List.stream()" because the return value of "com.sparta.msa_exam.order.entity.Order.getOrderProductList()" is null
영속성에서 저장이 문제구나 하는 생각에
List<OrderProductDto> orderProductDtoList = Optional.ofNullable(order.getOrderProductList()) .orElse(Collections.emptyList()).stream() .map(orderProduct -> new OrderProductDto( orderProduct.getProductId(), orderProduct.getQuantity().getQuantity()) ).toList();
@Transactional public CreateOrderResponseDto createOrder(Long userId, CreateOrderRequestDto requestDto) { Order order = Order.builder() .userId(userId) .orderProductList(new ArrayList<>()) .build(); order = orderRepository.saveAndFlush(order); // 이게 답이었다.
마지막부분을 save 대신 saveAndFlush로 날리니 어찌 해결은 되었다.
그런데 또 이어서 에러가 터진다.
SimpleMessageConverter only supports String, byte[] and Serializable payloads, received: com.sparta.msa_exam.order.event.OrderCreateEvent
SimpleMessageConverter는 String, byte[], Serializable 인터페이스를 구현한 객체만 지원한다.
그래서 해당 객체를 직렬화 해주면 된다.
또한 잭슨 컨터버를 추가하였다.
public class OrderCreateEvent implements Serializable { private Long orderId; private Long userId; private List<OrderProductDto> orderProductDtoList; }
@Bean public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate template = new RabbitTemplate(connectionFactory); template.setMessageConverter(jackson2JsonMessageConverter()); return template; } @Bean public Jackson2JsonMessageConverter jackson2JsonMessageConverter() { return new Jackson2JsonMessageConverter(); }
그러고 실행하니
{ "orderId": 1, "userId": 1, "totalPrice": 0, "failedProductList": [ 1, 2, 3 ] } 실패에 담겼다.
주문 생성 실패 리스트에 담겼다.
for (Long productId : requestDto.getProductIdList()) { try { GetProductInfoResponseDto responseDto = productClient.getProductInfo(productId); OrderProduct orderProduct = new OrderProduct(order, productId, Price.of(responseDto.getPrice()), Quantity.of(responseDto.getQuantity())); order.addOrderProduct(orderProduct); } catch (CustomException e) { failedProductList.add(productId); } }
이는 역직렬화를 통해 해결하였다.
여기까지 완벽한 트러블슈팅이었으나,
애플리케이션 실행 시에 강제로 메세지큐가 실행되어 에러가 계속 발생하는 문제가 생겼다.
여러 시도 끝에 메세지큐에 남아있는 요청이 문제라는 것을 확인하였다.
그래서 메세지큐 도커 내부에서 메세지큐를 비워주었다.
"명령어"로
docker exec -it rabbitmq /bin/bash rabbitmqctl purge_queue order.created.queue exit
래빗MQ 웹으로 들어가는 관리자페이지는 default 아이디, 패스워드를 입력하니 권한이 없다고 한다.
그냥 잘 아는 도커로 해야겠다.
'스파르타 심화 > MSA 개인프로젝트' 카테고리의 다른 글
프로젝트 시작 - 대략적인 구상 (0) 2024.11.30