iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Software Development

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

Day 15|部分/全部成交與撤單:回簿、移除與 REST 控制

  • 分享至 

  • xImage
  •  

1. 部分 vs. 全部成交:狀態怎麼走

在主回圈內,我已 Math.min() 比較這次交易的買單跟賣單後後算出本次成交量,然後同步更新兩者的剩餘量。

  • 對手單還有量:我把更新後的對手單重新 addOrder() 回訂單簿。
  • 對手單吃完:我呼叫 removeOrder() 從訂單簿與詳情、使用者索引完全移除。
    這樣的處理能有效避免「幽靈」訂單,也讓後續查詢能即時反映真實掛簿。

2. 撤單:REST 介面與服務

我提供 DELETE /v1/order/cancel,收一個 OrderCancelEvent。流程是 Controller → Service → Redis 服務。

// OrderController.java
@DeleteMapping("cancel")
public boolean cancelOrder(@RequestBody OrderCancelEvent event) {
  return orderCancelService.execute(event);
}
// OrderCancelService.java
public boolean execute(OrderCancelEvent cancelEvent) {
  return redisService.cancelOrder(cancelEvent);
}
// RedisOrderBookService.cancelOrder(...)
public boolean cancelOrder(OrderCancelEvent event) {
  String orderIdKey = "order:" + event.getOrderId();
  String json = redisTemplate.opsForValue().get(orderIdKey);
  if (json == null) return false;

  OrderCreatedEvent order = objectMapper.readValue(json, OrderCreatedEvent.class);
  String bookKey = order.getOrderType().equalsIgnoreCase("BUY") ? BUY_ORDERBOOK_KEY : SELL_ORDERBOOK_KEY;

  boolean removed = redisTemplate.opsForZSet()
      .remove(bookKey, event.getOrderId().toString()) > 0;

  if (removed) {
    redisTemplate.delete(orderIdKey);
    redisTemplate.opsForSet()
        .remove("user:" + order.getUserId() + ":orders", event.getOrderId().toString());
  }
  return removed;
}

我在這裡的選擇

  • 撤單採「即時移除」:與我目前使用 ZSET 作為價位集合的方式相容,操作直觀。
  1. 查詢:檢視使用者目前的掛單
    GET /v1/order/query/{userId} 走的是「使用者索引 → 訂單詳情」的模式。這個API用來給user查詢現在他存在訂單簿中的訂單,簡單的透過傳入userid檢索redis的key值後找到他的訂單們。

上一篇
Day 14|訂單媒合Lua 原子操作:對手方最優價 → 取單 → 移除(一次完成
下一篇
Day 15|多節點不搶單:Queue 分工 × Lua 原子更新的雙保險
系列文
事件驅動電力交易平台:Spring Boot 實戰16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言