12/23

졸용·2025년 12월 23일

TIL

목록 보기
141/144

🔹 outbox 패턴 적용 Repository

🔸 JpaOrderOutboxEventRepository

package chill_logistics.order_server.infrastructure.repository;

import chill_logistics.order_server.domain.entity.OrderOutboxEvent;
import chill_logistics.order_server.domain.entity.OrderOutboxStatus;
import jakarta.persistence.LockModeType;
import java.util.List;
import java.util.UUID;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface JpaOrderOutboxEventRepository extends JpaRepository<OrderOutboxEvent, UUID> {

    /* 처리 대상으로 가져와서 락 거는 목적 용도 (PENDING + Lock + 오래된 순) */
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("SELECT e FROM OrderOutboxEvent e " +
           "WHERE e.orderOutboxStatus = :status " +
           "ORDER BY e.createdAt ASC")
    List<OrderOutboxEvent> findPendingEventsForUpdate(
        @Param("status") OrderOutboxStatus status,
        Pageable pageable);

    /* 검색/관리용 (status/orderId 조건 검색) */
    @Query("SELECT e FROM OrderOutboxEvent e " +
           "WHERE (:status IS NULL OR e.orderOutboxStatus = :status) " +
           "AND (:orderId IS NULL OR e.orderId = :orderId) " +
           "ORDER BY e.createdAt ASC")
    List<OrderOutboxEvent> findOutboxEvents(
        @Param("status") OrderOutboxStatus status,
        @Param("orderId") UUID orderId,
        Pageable pageable);

    /* FAILED 모니터링/조회용 */
    @Query("SELECT e FROM OrderOutboxEvent e " +
           "WHERE e.orderOutboxStatus = 'FAILED' " +
           "ORDER BY e.lastRetryAt DESC, e.createdAt DESC")
    List<OrderOutboxEvent> findFailedEvents(Pageable pageable);
}

🔸 OrderOutboxEventRepositoryAdapter

package chill_logistics.order_server.infrastructure.repository;

import chill_logistics.order_server.domain.entity.OrderOutboxEvent;
import chill_logistics.order_server.domain.entity.OrderOutboxStatus;
import chill_logistics.order_server.domain.repository.OrderOutboxEventRepository;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;

@RequiredArgsConstructor
public class OrderOutboxEventRepositoryAdapter implements OrderOutboxEventRepository {

    private final JpaOrderOutboxEventRepository jpaRepository;

    @Override
    public OrderOutboxEvent save(OrderOutboxEvent event) {
        return jpaRepository.save(event);
    }

    @Override
    public Optional<OrderOutboxEvent> findById(UUID id) {
        return jpaRepository.findById(id);
    }

    @Override
    public List<OrderOutboxEvent> findPendingEvents(OrderOutboxStatus status, int batchSize) {
        return jpaRepository.findPendingEventsForUpdate(status, PageRequest.of(0, batchSize));
    }

    @Override
    public List<OrderOutboxEvent> findOutboxEvents(OrderOutboxStatus status, UUID orderId, int page, int size) {
        return jpaRepository.findOutboxEvents(status, orderId, PageRequest.of(page, size));
    }

    @Override
    public List<OrderOutboxEvent> findFailedEvents(int page, int size) {
        return jpaRepository.findFailedEvents(PageRequest.of(page, size));
    }
}

🔸 OrderOutboxEventRepository

package chill_logistics.order_server.domain.repository;

import chill_logistics.order_server.domain.entity.OrderOutboxEvent;
import chill_logistics.order_server.domain.entity.OrderOutboxStatus;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface OrderOutboxEventRepository {

    OrderOutboxEvent save(OrderOutboxEvent orderOutboxEvent);

    Optional<OrderOutboxEvent> findById(UUID orderOutboxEventId);

    List<OrderOutboxEvent> findPendingEvents(OrderOutboxStatus status, int batchSize);

    List<OrderOutboxEvent> findOutboxEvents(OrderOutboxStatus status, UUID orderId, int page, int size);

    List<OrderOutboxEvent> findFailedEvents(int page, int size);
}
profile
꾸준한 공부만이 답이다

0개의 댓글