iT邦幫忙

2025 iThome 鐵人賽

DAY 11
0
Software Development

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

Day 11|查得見的進度:Order Service 的訂單狀態追蹤

  • 分享至 

  • xImage
  •  

前面幾篇把「建立 → 核定 →(待)撮合」串起來了,但用戶會需要知道:我這張單現在到哪了?
目前我用 in-memory Map 做最簡單的讀模型:PENDING → CREATED → MATCHED)。

1.為什麼先用 Map?

• 現在的目標是把事件流跑順、體驗整體設計;
• Map 查詢快,程式簡單;
• 不牽涉額外的儲存與運維。

2.生命週期與事件關聯

• 使用者送單:Order 先 markPending(orderId)
• Wallet 核定:Order 這邊收到 OrderCreatedEvent 後 → markCreated(orderId)(訊號來自 Day 9,10的事件)

3.實作範例(Order 端)

@Component
public class OrderStatusTracker {

  private final Map<UUID, OrderStatus> status = new ConcurrentHashMap<>();

  public void markPending(UUID id) { status.put(id, OrderStatus.PENDING); }

  @RabbitListener(queues = ORDER_CREATED_QUEUE)
  public void onOrderCreated(OrderCreatedEvent e) {
    status.put(e.getOrderId(), OrderStatus.CREATED);
  }

  public OrderStatus get(UUID id) { return status.getOrDefault(id, OrderStatus.UNKNOWN); }
}

• 在 PlaceBuyOrderService.execute(...) 建立事件前先 markPending(orderId)(orderId 是建立事件時就生成的)。
• ORDER_CREATED_QUEUE 綁定 order.created,收到 Wallet 的回報就更新狀態(事件結構同 Day 10)。

4. 查詢 API

@RestController
@RequestMapping("/orders")
@RequiredArgsConstructor
public class OrderQueryController {
  private final OrderStatusTracker tracker;

  @GetMapping("/{id}/status")
  public ResponseEntity<String> status(@PathVariable UUID id) {
    return ResponseEntity.ok(tracker.get(id).name());
  }
}

這樣前端就能用 polling 看到最終一致的狀態;若 PENDING 停太久,UI 可以提醒使用者稍後再查或提供「重新整理」動作。

5.小結

Map 版讀模型雖然簡單,但不需使用額外服務即可完成目的:
把建立 → 核定 → 可撮合跑穩、看得見;未來再把 MATCHED 加進來,或替換為 Redis/Mongo 都很自然(如未來真的要上更多節點再談儲存層也可以簡單轉換)。


上一篇
Day 10|把「核定完成」送去撮合:OrderCreatedEvent 的語意與落點
下一篇
Day 12|撮合事件流全覽:從核定回報 → 撮合 → 成交回寫
系列文
事件驅動電力交易平台:Spring Boot 實戰12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言