diff --git a/src/main/java/com/coinflow/order/service/AcceptedOrderService.java b/src/main/java/com/coinflow/order/service/AcceptedOrderService.java index fd67ef9..764ac46 100644 --- a/src/main/java/com/coinflow/order/service/AcceptedOrderService.java +++ b/src/main/java/com/coinflow/order/service/AcceptedOrderService.java @@ -14,7 +14,6 @@ import com.coinflow.order.service.command.CreateOrderCommand; import com.coinflow.order.service.command.MarketOrderCommandQueue; import com.coinflow.order.service.lock.OrderAssetLockService; -import com.coinflow.order.service.metrics.OrderCreateStageRecorder; import com.coinflow.order.service.processor.AcceptedOrderProcessor; import com.coinflow.order.service.support.ClientOrderIdService; import com.coinflow.order.service.support.MarketSequenceAllocator; @@ -38,7 +37,6 @@ public class AcceptedOrderService { private final OrderAssetLockService orderAssetLockService; private final MarketOrderCommandQueue marketOrderCommandQueue; private final MarketSequenceAllocator marketSequenceAllocator; - private final OrderCreateStageRecorder stageRecorder; private final AcceptedOrderProcessor acceptedOrderProcessor; private final ClientOrderIdService clientOrderIdService; private final TransactionTemplate transactionTemplate; @@ -51,7 +49,6 @@ public AcceptedOrderService( OrderAssetLockService orderAssetLockService, MarketOrderCommandQueue marketOrderCommandQueue, MarketSequenceAllocator marketSequenceAllocator, - OrderCreateStageRecorder stageRecorder, AcceptedOrderProcessor acceptedOrderProcessor, ClientOrderIdService clientOrderIdService, PlatformTransactionManager transactionManager @@ -63,7 +60,6 @@ public AcceptedOrderService( this.orderAssetLockService = orderAssetLockService; this.marketOrderCommandQueue = marketOrderCommandQueue; this.marketSequenceAllocator = marketSequenceAllocator; - this.stageRecorder = stageRecorder; this.acceptedOrderProcessor = acceptedOrderProcessor; this.clientOrderIdService = clientOrderIdService; this.transactionTemplate = new TransactionTemplate(transactionManager); @@ -112,10 +108,7 @@ private Order acceptInTransaction( ) { clientOrderIdService.validateUnique(currentUserId, request, market, side); - Long sequence = stageRecorder.record( - market.getSymbol(), side, "sequence_allocate", - () -> marketSequenceAllocator.nextSequence(market.getId()) - ); + Long sequence = marketSequenceAllocator.nextSequence(market.getId()); Wallet wallet = orderAssetLockService.lockTakerWallet(currentUserId, command); Order order = Order.accepted( currentUserId, market.getId(), market.getSymbol(), @@ -124,15 +117,11 @@ private Order acceptInTransaction( command.lockedAsset(), command.lockedAmount(), sequence, request.clientOrderId() ); - stageRecorder.record(market.getSymbol(), side, "order_save", - () -> orderRepository.save(order)); + orderRepository.save(order); WalletLedger orderLockLedger = orderAssetLockService.createOrderLockLedger(wallet, order, command); orderAssetLockService.saveOrderLockLedger(orderLockLedger, command); - stageRecorder.record(market.getSymbol(), side, "order_accepted_event_save", () -> { - eventRecorder.recordOrderAccepted(order); - return null; - }); + eventRecorder.recordOrderAccepted(order); TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override @@ -148,7 +137,7 @@ private boolean enqueueAcceptedOrder(Market market, OrderSide side, Long orderId market, side, orderId, - () -> acceptedOrderProcessor.processAcceptedOrder(market, side, orderId) + () -> acceptedOrderProcessor.processAcceptedOrder(market, orderId) ); } diff --git a/src/main/java/com/coinflow/order/service/OrderService.java b/src/main/java/com/coinflow/order/service/OrderService.java index 65faf5b..58a406b 100644 --- a/src/main/java/com/coinflow/order/service/OrderService.java +++ b/src/main/java/com/coinflow/order/service/OrderService.java @@ -55,8 +55,6 @@ public OrderService( } public CreateOrderResponse createOrder(Long currentUserId, CreateOrderRequest request) { - long createStartedAt = System.nanoTime(); - Market market = marketRepository.findBySymbol(request.market()) .orElseThrow(() -> new ApiException(ErrorCode.MARKET_NOT_FOUND)); CreateOrderCommand command = orderCreateValidator.validate(market, request); @@ -66,7 +64,7 @@ public CreateOrderResponse createOrder(Long currentUserId, CreateOrderRequest re return marketOrderCommandQueue.submit( market, side, - () -> syncOrderProcessor.process(currentUserId, request, market, command, createStartedAt) + () -> syncOrderProcessor.process(currentUserId, request, market, command) ); } diff --git a/src/main/java/com/coinflow/order/service/metrics/OrderTransactionLifecycleRecorder.java b/src/main/java/com/coinflow/order/service/metrics/OrderTransactionLifecycleRecorder.java deleted file mode 100644 index 2c6a7a2..0000000 --- a/src/main/java/com/coinflow/order/service/metrics/OrderTransactionLifecycleRecorder.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.coinflow.order.service.metrics; - -import com.coinflow.order.domain.OrderSide; -import org.springframework.stereotype.Component; - -@Component -public class OrderTransactionLifecycleRecorder { - - private final OrderCreateStageRecorder stageRecorder; - - public OrderTransactionLifecycleRecorder(OrderCreateStageRecorder stageRecorder) { - this.stageRecorder = stageRecorder; - } - - public Metrics start(String marketSymbol, OrderSide side, long templateStartedAt) { - return new Metrics(marketSymbol, side, templateStartedAt); - } - - public class Metrics { - private final String marketSymbol; - private final OrderSide side; - private final long templateStartedAt; - - private long callbackStartedAt = -1L; - private long callbackFinishedAt = -1L; - private long beforeCommitAt = -1L; - private long beforeCompletionAt = -1L; - private long afterCommitStartedAt = -1L; - private long afterCommitFinishedAt = -1L; - private long afterCompletionStartedAt = -1L; - private long afterCompletionFinishedAt = -1L; - - private Metrics(String marketSymbol, OrderSide side, long templateStartedAt) { - this.marketSymbol = marketSymbol; - this.side = side; - this.templateStartedAt = templateStartedAt; - } - - public void recordCallbackStarted() { - callbackStartedAt = System.nanoTime(); - stageRecorder.record(marketSymbol, side, "transaction_begin", - callbackStartedAt - templateStartedAt); - } - - public void recordCallbackFinished() { - callbackFinishedAt = System.nanoTime(); - } - - public void recordBeforeCommit() { - beforeCommitAt = System.nanoTime(); - if (callbackFinishedAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_before_commit_wait", - beforeCommitAt - callbackFinishedAt); - } - } - - public void recordBeforeCompletion() { - beforeCompletionAt = System.nanoTime(); - if (beforeCommitAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_before_completion", - beforeCompletionAt - beforeCommitAt); - } - } - - public void recordAfterCommitStarted() { - afterCommitStartedAt = System.nanoTime(); - if (beforeCompletionAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_commit", - afterCommitStartedAt - beforeCompletionAt); - } - } - - public void recordAfterCommitFinished() { - afterCommitFinishedAt = System.nanoTime(); - if (afterCommitStartedAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_after_commit_callbacks", - afterCommitFinishedAt - afterCommitStartedAt); - } - } - - public void recordAfterCompletionStarted() { - afterCompletionStartedAt = System.nanoTime(); - if (afterCommitFinishedAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_after_commit_to_completion", - afterCompletionStartedAt - afterCommitFinishedAt); - } - } - - public void recordAfterCompletionFinished() { - afterCompletionFinishedAt = System.nanoTime(); - if (afterCompletionStartedAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_after_completion_callbacks", - afterCompletionFinishedAt - afterCompletionStartedAt); - } - } - - public void recordTemplateReturned(long templateFinishedAt) { - if (callbackFinishedAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_after_callback", - templateFinishedAt - callbackFinishedAt); - } - if (afterCompletionFinishedAt > 0) { - stageRecorder.record(marketSymbol, side, "transaction_completion_to_return", - templateFinishedAt - afterCompletionFinishedAt); - } - } - } -} diff --git a/src/main/java/com/coinflow/order/service/processor/AcceptedOrderProcessor.java b/src/main/java/com/coinflow/order/service/processor/AcceptedOrderProcessor.java index 9ca3c31..fbf9ec2 100644 --- a/src/main/java/com/coinflow/order/service/processor/AcceptedOrderProcessor.java +++ b/src/main/java/com/coinflow/order/service/processor/AcceptedOrderProcessor.java @@ -5,13 +5,11 @@ import com.coinflow.event.service.DomainEventRecorder; import com.coinflow.market.domain.Market; import com.coinflow.order.domain.Order; -import com.coinflow.order.domain.OrderSide; import com.coinflow.order.domain.OrderStatus; import com.coinflow.order.matching.MatchResult; import com.coinflow.order.matching.MatchingEngine; import com.coinflow.order.matching.OrderBookRecoveryService; import com.coinflow.order.repository.OrderRepository; -import com.coinflow.order.service.metrics.OrderCreateStageRecorder; import com.coinflow.order.service.settlement.OrderSettlementService; import com.coinflow.trade.domain.Trade; import com.coinflow.wallet.domain.LedgerType; @@ -37,7 +35,6 @@ public class AcceptedOrderProcessor { private final OrderBookRecoveryService orderBookRecoveryService; private final DomainEventRecorder eventRecorder; private final OrderSettlementService orderSettlementService; - private final OrderCreateStageRecorder stageRecorder; private final TransactionTemplate transactionTemplate; public AcceptedOrderProcessor( @@ -47,7 +44,6 @@ public AcceptedOrderProcessor( OrderBookRecoveryService orderBookRecoveryService, DomainEventRecorder eventRecorder, OrderSettlementService orderSettlementService, - OrderCreateStageRecorder stageRecorder, PlatformTransactionManager transactionManager ) { this.orderRepository = orderRepository; @@ -56,20 +52,19 @@ public AcceptedOrderProcessor( this.orderBookRecoveryService = orderBookRecoveryService; this.eventRecorder = eventRecorder; this.orderSettlementService = orderSettlementService; - this.stageRecorder = stageRecorder; this.transactionTemplate = new TransactionTemplate(transactionManager); } - public void processAcceptedOrder(Market market, OrderSide side, Long orderId) { + public void processAcceptedOrder(Market market, Long orderId) { try { - processAcceptedOrderInternal(market, side, orderId); + processAcceptedOrderInternal(market, orderId); } catch (Throwable e) { log.warn("Accepted order processing failed. orderId={}, error={}", orderId, e.getMessage(), e); rejectAcceptedOrder(orderId, e.getClass().getSimpleName()); } } - private void processAcceptedOrderInternal(Market market, OrderSide side, Long orderId) { + private void processAcceptedOrderInternal(Market market, Long orderId) { transactionTemplate.execute(status -> { Order order = orderRepository.findByIdWithLock(orderId) .orElseThrow(() -> new ApiException(ErrorCode.ORDER_NOT_FOUND)); @@ -78,37 +73,36 @@ private void processAcceptedOrderInternal(Market market, OrderSide side, Long or } order.open(); - List plan = stageRecorder.record( - market.getSymbol(), side, "matching_plan", - () -> matchingEngine.planMatchRejectingSelfTrade(market, order) - ); + List plan = matchingEngine.planMatchRejectingSelfTrade(market, order); List autoCanceledMakers = new ArrayList<>(); - List trades = stageRecorder.record( - market.getSymbol(), side, "settlement", - () -> orderSettlementService.settle(market, order, plan, autoCanceledMakers, null, false) - ); + List trades = orderSettlementService.settle(market, order, plan, autoCanceledMakers, null, false); - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - @Override - public void afterCommit() { - long orderBookApplyStartedAt = System.nanoTime(); - try { - matchingEngine.applyMatchPlan(market, order, plan); - autoCanceledMakers.forEach(canceledMaker -> - matchingEngine.cancelOrder(market.getSymbol(), canceledMaker)); - } catch (Exception e) { - log.error("오더북 applyMatchPlan 실패: orderId={}, DB 체결 내역 기반 재빌드 시도", order.getId(), e); - orderBookRecoveryService.rebuildAfterApplyFailure(market.getId()); - } finally { - stageRecorder.record(market.getSymbol(), side, "orderbook_after_commit", - System.nanoTime() - orderBookApplyStartedAt); - } - } - }); + registerOrderBookSynchronization(market, order, plan, autoCanceledMakers); return trades; }); } + private void registerOrderBookSynchronization( + Market market, + Order order, + List plan, + List autoCanceledMakers + ) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + try { + matchingEngine.applyMatchPlan(market, order, plan); + autoCanceledMakers.forEach(canceledMaker -> + matchingEngine.cancelOrder(market.getSymbol(), canceledMaker)); + } catch (Exception e) { + log.error("오더북 applyMatchPlan 실패: orderId={}, DB 체결 내역 기반 재빌드 시도", order.getId(), e); + orderBookRecoveryService.rebuildAfterApplyFailure(market.getId()); + } + } + }); + } + private void rejectAcceptedOrder(Long orderId, String reason) { transactionTemplate.execute(status -> { Order order = orderRepository.findByIdWithLock(orderId) @@ -130,5 +124,4 @@ private void rejectAcceptedOrder(Long orderId, String reason) { return null; }); } - } diff --git a/src/main/java/com/coinflow/order/service/processor/SyncOrderProcessor.java b/src/main/java/com/coinflow/order/service/processor/SyncOrderProcessor.java index e74aff0..7d665f8 100644 --- a/src/main/java/com/coinflow/order/service/processor/SyncOrderProcessor.java +++ b/src/main/java/com/coinflow/order/service/processor/SyncOrderProcessor.java @@ -5,7 +5,6 @@ import com.coinflow.event.service.DomainEventRecorder; import com.coinflow.market.domain.Market; import com.coinflow.order.domain.Order; -import com.coinflow.order.domain.OrderSide; import com.coinflow.order.dto.CreateOrderRequest; import com.coinflow.order.dto.CreateOrderResponse; import com.coinflow.order.matching.MatchResult; @@ -14,8 +13,6 @@ import com.coinflow.order.repository.OrderRepository; import com.coinflow.order.service.command.CreateOrderCommand; import com.coinflow.order.service.lock.OrderAssetLockService; -import com.coinflow.order.service.metrics.OrderCreateStageRecorder; -import com.coinflow.order.service.metrics.OrderTransactionLifecycleRecorder; import com.coinflow.order.service.settlement.OrderSettlementService; import com.coinflow.order.service.support.ClientOrderIdService; import com.coinflow.order.service.support.MarketSequenceAllocator; @@ -44,8 +41,6 @@ public class SyncOrderProcessor { private final OrderAssetLockService orderAssetLockService; private final OrderSettlementService orderSettlementService; private final MarketSequenceAllocator marketSequenceAllocator; - private final OrderCreateStageRecorder stageRecorder; - private final OrderTransactionLifecycleRecorder transactionLifecycleRecorder; private final ClientOrderIdService clientOrderIdService; private final TransactionTemplate transactionTemplate; @@ -57,8 +52,6 @@ public SyncOrderProcessor( OrderAssetLockService orderAssetLockService, OrderSettlementService orderSettlementService, MarketSequenceAllocator marketSequenceAllocator, - OrderCreateStageRecorder stageRecorder, - OrderTransactionLifecycleRecorder transactionLifecycleRecorder, ClientOrderIdService clientOrderIdService, PlatformTransactionManager transactionManager ) { @@ -69,8 +62,6 @@ public SyncOrderProcessor( this.orderAssetLockService = orderAssetLockService; this.orderSettlementService = orderSettlementService; this.marketSequenceAllocator = marketSequenceAllocator; - this.stageRecorder = stageRecorder; - this.transactionLifecycleRecorder = transactionLifecycleRecorder; this.clientOrderIdService = clientOrderIdService; this.transactionTemplate = new TransactionTemplate(transactionManager); } @@ -79,37 +70,16 @@ public CreateOrderResponse process( Long currentUserId, CreateOrderRequest request, Market market, - CreateOrderCommand command, - long createStartedAt + CreateOrderCommand command ) { - OrderSide side = command.side(); - - long transactionTemplateStartedAt = System.nanoTime(); - OrderTransactionLifecycleRecorder.Metrics transactionMetrics = transactionLifecycleRecorder.start( - market.getSymbol(), side, transactionTemplateStartedAt); try { - try { - return transactionTemplate.execute(status -> executeInTransaction( - currentUserId, - request, - market, - command, - side, - transactionMetrics - )); - } catch (DataIntegrityViolationException e) { - if (request.clientOrderId() != null && clientOrderIdService.isDuplicateConstraintViolation(e)) { - throw new ApiException(ErrorCode.DUPLICATE_CLIENT_ORDER_ID); - } - throw e; + return transactionTemplate.execute(status -> + executeInTransaction(currentUserId, request, market, command)); + } catch (DataIntegrityViolationException e) { + if (request.clientOrderId() != null && clientOrderIdService.isDuplicateConstraintViolation(e)) { + throw new ApiException(ErrorCode.DUPLICATE_CLIENT_ORDER_ID); } - } finally { - long transactionTemplateFinishedAt = System.nanoTime(); - stageRecorder.record(market.getSymbol(), side, "transaction_template", - transactionTemplateFinishedAt - transactionTemplateStartedAt); - transactionMetrics.recordTemplateReturned(transactionTemplateFinishedAt); - stageRecorder.record(market.getSymbol(), side, "total", - System.nanoTime() - createStartedAt); + throw e; } } @@ -117,49 +87,22 @@ private CreateOrderResponse executeInTransaction( Long currentUserId, CreateOrderRequest request, Market market, - CreateOrderCommand command, - OrderSide side, - OrderTransactionLifecycleRecorder.Metrics transactionMetrics + CreateOrderCommand command ) { - transactionMetrics.recordCallbackStarted(); - long transactionCallbackStartedAt = System.nanoTime(); - try { - Long sequence = stageRecorder.record( - market.getSymbol(), side, "sequence_allocate", - () -> marketSequenceAllocator.nextSequence(market.getId()) - ); - Wallet wallet = orderAssetLockService.lockTakerWallet(currentUserId, command); - Order order = createAndSaveOrder(currentUserId, request, market, command, sequence); - WalletLedger orderLockLedger = orderAssetLockService.createOrderLockLedger(wallet, order, command); - - List plan = stageRecorder.record( - market.getSymbol(), side, "matching_plan", - () -> matchingEngine.planMatchRejectingSelfTrade(market, order) - ); - List autoCanceledMakers = new ArrayList<>(); - List trades = stageRecorder.record( - market.getSymbol(), side, "settlement", - () -> orderSettlementService.settle(market, order, plan, autoCanceledMakers, orderLockLedger) - ); - if (trades.isEmpty()) { - recordAcceptedOrderWithoutTrade(market, side, order, orderLockLedger, command); - } - - registerOrderBookSynchronization( - market, - side, - order, - plan, - autoCanceledMakers, - transactionMetrics - ); - - return CreateOrderResponse.of(order, trades); - } finally { - transactionMetrics.recordCallbackFinished(); - stageRecorder.record(market.getSymbol(), side, "transaction_callback", - System.nanoTime() - transactionCallbackStartedAt); + Long sequence = marketSequenceAllocator.nextSequence(market.getId()); + Wallet wallet = orderAssetLockService.lockTakerWallet(currentUserId, command); + Order order = createAndSaveOrder(currentUserId, request, market, command, sequence); + WalletLedger orderLockLedger = orderAssetLockService.createOrderLockLedger(wallet, order, command); + + List plan = matchingEngine.planMatchRejectingSelfTrade(market, order); + List autoCanceledMakers = new ArrayList<>(); + List trades = orderSettlementService.settle(market, order, plan, autoCanceledMakers, orderLockLedger); + if (trades.isEmpty()) { + recordAcceptedOrderWithoutTrade(order, orderLockLedger, command); } + + registerOrderBookSynchronization(market, order, plan, autoCanceledMakers); + return CreateOrderResponse.of(order, trades); } private Order createAndSaveOrder( @@ -176,48 +119,28 @@ private Order createAndSaveOrder( command.lockedAsset(), command.lockedAmount(), sequence, request.clientOrderId() ); - stageRecorder.record(market.getSymbol(), command.side(), "order_save", - () -> orderRepository.save(order)); + orderRepository.save(order); return order; } private void recordAcceptedOrderWithoutTrade( - Market market, - OrderSide side, Order order, WalletLedger orderLockLedger, CreateOrderCommand command ) { - stageRecorder.record(market.getSymbol(), side, "order_accepted_event_save", () -> { - eventRecorder.recordOrderAccepted(order); - return null; - }); + eventRecorder.recordOrderAccepted(order); orderAssetLockService.saveOrderLockLedger(orderLockLedger, command); } private void registerOrderBookSynchronization( Market market, - OrderSide side, Order order, List plan, - List autoCanceledMakers, - OrderTransactionLifecycleRecorder.Metrics transactionMetrics + List autoCanceledMakers ) { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - @Override - public void beforeCommit(boolean readOnly) { - transactionMetrics.recordBeforeCommit(); - } - - @Override - public void beforeCompletion() { - transactionMetrics.recordBeforeCompletion(); - } - @Override public void afterCommit() { - transactionMetrics.recordAfterCommitStarted(); - long orderBookApplyStartedAt = System.nanoTime(); try { matchingEngine.applyMatchPlan(market, order, plan); autoCanceledMakers.forEach(canceledMaker -> @@ -225,18 +148,8 @@ public void afterCommit() { } catch (Exception e) { log.error("오더북 applyMatchPlan 실패: orderId={}, DB 체결 내역 기반 재빌드 시도", order.getId(), e); orderBookRecoveryService.rebuildAfterApplyFailure(market.getId()); - } finally { - stageRecorder.record(market.getSymbol(), side, "orderbook_after_commit", - System.nanoTime() - orderBookApplyStartedAt); - transactionMetrics.recordAfterCommitFinished(); } } - - @Override - public void afterCompletion(int status) { - transactionMetrics.recordAfterCompletionStarted(); - transactionMetrics.recordAfterCompletionFinished(); - } }); } }