iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Software Development

事件驅動電力交易平台:Spring Boot 實戰系列 第 9

Day 9|Wallet Consumer :資產驗證與鎖定的交易邏輯

  • 分享至 

  • xImage
  •  

Wallet 是這條事件流的「核定關」。本篇把 Listener 的行為逐段拆解,說清楚 BUY / SELL 的條件與凍結欄位。

1.Listener 的輸入/輸出與流程

  • 輸入:OrderCreateEvent(Order 送來)
  • 處理:驗證餘額/庫存 → 鎖定(從 available 移到 locked)
  • 輸出:OrderCreatedEvent(可撮合)
    核心程式就在
CreateOrderListener.onOrderCreate(...):
@RabbitListener(queues = ORDER_CREATE_QUEUE)
public void onOrderCreate(OrderCreateEvent event) {
  if (!isWalletEnough(event)) { /*...*/ }
  if (!isWalletEnoughForSell(event)) { /*...*/ }

  WalletEntity wallet = walletRepository.findByUserId(event.getUserId());

  if ("BUY".equals(event.getOrderType())) {
    int cost = event.getPrice() * event.getAmount();
    wallet.setAvailableCurrency(wallet.getAvailableCurrency() - cost);
    wallet.setLockedCurrency(wallet.getLockedCurrency() + cost);
  } else if ("SELL".equals(event.getOrderType())) {
    int quantity = event.getAmount();
    wallet.setAvailableAmount(wallet.getAvailableAmount() - quantity);
    wallet.setLockedAmount(wallet.getLockedAmount() + quantity);
  }
  walletRepository.save(wallet);

  // 發出 OrderCreatedEvent
  rabbitTemplate.convertAndSend(ORDER_EXCHANGE, ORDER_CREATED_KEY, toCreated(event));
}

isWalletEnough() 與 isWalletEnoughForSell() 會先查使用者錢包並計算是否足夠,避免超賣/超買。

2.為什麼要「先凍結」?

把可用資產轉到鎖定欄位(available → locked)是交易系統的基本保護:
• 撮合前就確保資金/庫存到位
• 後續若撤單,再從 locked 還回可用

3.輸出 OrderCreatedEvent 的意義

核定成功才會送這個事件,代表可以進入撮合。欄位直接沿用原事件,用同一個 exchange、不同 routing key。

4.小結

Wallet 把「資產可用性」收斂成一個明確訊號(created)。這樣上游不用等、下游不用猜,整條鏈路的責任邊界就很清楚。


上一篇
Day 8|AMQP 組態與命名:支撐現有事件流的最小集合
系列文
事件驅動電力交易平台:Spring Boot 實戰9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言