Skip to main content

事件佇列(EventQueue)

Skalds 系統中的 EventQueue 是實現模組間鬆耦合、高效能通訊的關鍵元件。它基於 Kafka 3.9.0+,採用發佈/訂閱(Pub/Sub)機制,負責 System Controller、Task Generator(Skald)、Task Worker 之間的事件傳遞與狀態同步。EventQueue 具備高吞吐量、可靠性與彈性擴展能力,是分散式任務調度的核心通訊樞紐。


設計理念​

  • 事件驅動:所有任務建立、更新、取消等操作皆以事件形式流轉,確保狀態即時同步。
  • 鬆耦合架構:模組間僅透過事件佇列互動,降低耦合度,提升系統可維護性與擴展性。
  • 高可用與高效能:Kafka 支援多副本、分區與自動容錯,適合大規模分散式場景。
  • 無需 Zookeeper:採用 Kafka 3.9.0+,簡化部署與維護。

架構與角色​

EventQueue 主要負責以下模組間的事件通訊:

  • System Controller:發佈任務建立、更新、取消等事件,監控任務狀態。
  • Task Generator(Skald):接收並處理與自身 ID 相關的事件,分配任務給 Task Worker。
  • Task Worker:監聽自身任務 ID 的事件,動態調整運作參數或終止任務。

事件流示意:

[System Controller] <-> [EventQueue (Kafka)] <-> [Skald] <-> [Task Worker]

事件格式與資料結構​

EventQueue 所有事件皆以結構化 JSON 格式傳遞,並以 Pydantic 資料模型進行驗證。主要事件格式定義於 skalds/model/event.py (GitHub):

1. TaskEvent​

用於任務分配、更新、取消等事件。

class TaskEvent(BaseModel):
id: Optional[str] = None
title: Optional[str] = None
initiator: Optional[str] = None
recipient: Optional[str] = None
create_date_time: int = Field(default_factory=lambda: int(datetime.now().timestamp() * 1000), alias="createDateTime")
update_date_time: int = Field(default_factory=lambda: int(datetime.now().timestamp() * 1000), alias="updateDateTime")
task_ids: list = Field(..., alias="taskIds")
  • id:事件唯一識別碼(可選)
  • title:事件標題(可選)
  • initiator:事件發起者(可選)
  • recipient:事件接收者(可選)
  • createDateTime:建立時間(毫秒)
  • updateDateTime:更新時間(毫秒)
  • taskIds:受影響的任務 ID 列表(必填)

範例 payload​

{
"id": "evt_001",
"title": "Assign Task",
"initiator": "system_controller",
"recipient": "skalds-1",
"createDateTime": 1724131200000,
"updateDateTime": 1724131200000,
"taskIds": ["task_123"]
}

2. UpdateTaskWorkerEvent​

用於 Task Worker 參數熱更新事件。

class UpdateTaskWorkerEvent(BaseModel):
attachments: Optional[Any] = None # 必須為 Pydantic BaseModel 實例

@field_validator("attachments", mode="before")
def validate_attachments(cls, v):
if v is None:
return v
if not isinstance(v, BaseModel):
raise ValueError("attachments must be a Pydantic BaseModel instance")
return v
  • attachments:任務參數(必須為 Pydantic BaseModel 實例,型別安全)

範例 payload​

{
"attachments": {
"rtspUrl": "rtsp://192.168.1.1/camera1",
"fixFrame": 30
}
}

注意:
attachments 欄位必須符合對應 TaskWorker 的 Pydantic 資料模型,否則初始化或更新會失敗。


事件生命週期中的角色​

EventQueue 在任務生命週期的三大流程中扮演關鍵角色:

1. 任務建立​

  1. System Controller 產生任務後,發佈「新增任務事件」至 EventQueue。
  2. Skald 監聽並接收與自身 ID 相符的事件,建立 Task Worker。
  3. Task Worker 啟動後,向 Redis 註冊狀態與心跳。

2. 任務更新​

  1. System Controller 發佈「更新任務事件」至 EventQueue。
  2. Skald 接收事件,查詢任務細節,並將更新事件轉發給對應 Task Worker。
  3. Task Worker 監聽自身任務 ID 的事件,動態調整參數。

詳細流程請參考:任務生命週期

3. 任務取消​

  1. System Controller 發佈「取消任務事件」至 EventQueue,廣播給所有 Skald。
  2. Skald 查詢是否有對應 Task Worker,若有則關閉並釋放資源。

技術選型與 Kafka 架構​

  • Kafka 版本需求:建議 3.9.0+,支援無 Zookeeper 部署。
  • 高吞吐量:適合大量事件流與高併發場景。
  • 多副本與分區:提升容錯與擴展性。
  • Pub/Sub 機制:支援多消費者群組,靈活分發事件。

事件主題(Topic)設計​

參考 skalds/proxy/kafka.py (GitHub):

  • task.assign:任務分配事件
  • task.cancel:任務取消事件
  • task.update.attachment:任務參數更新事件
  • taskworker.update:Task Worker 狀態更新事件

注意:
不建議為每個任務動態產生 task.{task_id}.update 這類 per-task topic,因為會導致 topic 數量爆炸,嚴重影響 Kafka 效能與管理。
請統一使用共用 topic(如 task.update.attachment),並以 message key 或 payload 內的 task_id 做過濾與分流。


Kafka Proxy 介面說明​

skalds/proxy/kafka.py (GitHub) 提供高階 Kafka 操作介面,常用方法如下:

  • produce(topic_name, key, value):發佈事件至指定主題
  • KafkaConfig:配置 Kafka 連線參數(host、port、topic、群組 ID、認證等)
  • KafkaAdmin:主題管理(建立、刪除、查詢)

典型用法​

from skalds.proxy.kafka import KafkaProxy, KafkaConfig, KafkaTopic

# 初始化 Kafka 連線
kafka_proxy = KafkaProxy(KafkaConfig(host="localhost", port=9092))

# 發佈任務分配事件
from skalds.model.event import TaskEvent
event = TaskEvent(taskIds=["task_123"], initiator="system_controller", recipient="skalds-1")
kafka_proxy.produce(KafkaTopic.TASK_ASSIGN, key="task_123", value=event.model_dump_json())

# 發佈任務參數更新事件(共用 topic,key 為 task_id)
from skalds.model.event import UpdateTaskWorkerEvent
update_event = UpdateTaskWorkerEvent(attachments=...)
kafka_proxy.produce(KafkaTopic.TASK_UPDATE_ATTACHMENT, key="task_123", value=update_event.model_dump_json())

典型應用場景​

  • 任務分配與調度:System Controller 透過 EventQueue 將任務分配給指定 Skald。
  • 動態參數熱更新:任務執行中,透過 EventQueue 發送參數更新事件,Task Worker 即時調整。
  • 任務取消與終止:廣播取消事件,確保所有相關節點同步終止任務。
  • 狀態監控與回報:Task Worker 可回報狀態至 EventQueue,供 System Controller 監控。

效能優化與注意事項​

  • 分區設計:根據任務量與消費者數量合理設計分區數,提升併發處理能力。
  • 主題命名規範:建議以功能/任務類型區分主題,便於維護與監控。
  • 避免 per-task topic:所有事件請統一發佈至共用主題,避免動態產生大量 topic。
  • 連線重試與容錯:KafkaProxy 內建自動重連與錯誤處理機制,提升穩定性。
  • 安全性:如需雲端部署,建議啟用 SASL/SSL 認證。

部署建議​

  • 建議版本:Kafka 3.9.0+(無需 Zookeeper)
  • 多副本部署:提升高可用性與容錯能力
  • 監控工具:可結合 Kafka Manager、Prometheus 等工具監控主題流量與延遲
  • 與 Redis/MongoDB 整合:事件流僅負責通訊,狀態資料仍建議同步至 Redis/MongoDB

參考文件與延伸閱讀​


EventQueue 是 Skalds 分散式任務調度系統的通訊核心,正確設計與善用可大幅提升系統的即時性、彈性與可維護性。