fix: 恢复 HarnessRL HWPOD 重启幂等
This commit is contained in:
+38
-1
@@ -11,6 +11,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import calendar
|
||||
import ctypes
|
||||
import ctypes.wintypes as wt
|
||||
import hashlib
|
||||
@@ -61,6 +62,7 @@ LOG_DIR = CONFIG_DIR / "logs"
|
||||
UPDATE_DIR = CONFIG_DIR / "update"
|
||||
CONFIG_PATH = CONFIG_DIR / "config.json"
|
||||
STATE_PATH = CONFIG_DIR / "state.json"
|
||||
OPERATION_LEDGER_PATH = CONFIG_DIR / "hwpod-operations.json"
|
||||
LOG_PATH = LOG_DIR / "hwlab-node.log"
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
@@ -832,6 +834,7 @@ class WebSocketNodeClient:
|
||||
self.manual_stop = False
|
||||
self.connected = False
|
||||
self.diagnostic_cursor = 0
|
||||
self.operation_retention_seconds = 0
|
||||
|
||||
def start(self) -> None:
|
||||
if self.thread and self.thread.is_alive():
|
||||
@@ -972,18 +975,52 @@ class WebSocketNodeClient:
|
||||
message = json.loads(text)
|
||||
if message.get("type") == "ack" and message.get("requestId") == "register":
|
||||
self.connected = message.get("ok") is True
|
||||
self.operation_retention_seconds = safe_int(message.get("operationRetentionSeconds"), 0)
|
||||
self.bus.emit("connection", "connected" if self.connected else "error")
|
||||
self.bus.emit("log", f"注册结果: ok={message.get('ok')} message={message.get('message')}")
|
||||
return
|
||||
if message.get("type") != "hwpod-node-ops":
|
||||
return
|
||||
request_id = str(message.get("requestId") or "req_unknown")
|
||||
plan = message.get("plan") or {}
|
||||
plan_id = str(plan.get("planId") or request_id)
|
||||
ledger = self._operation_ledger()
|
||||
existing = ledger.get(plan_id)
|
||||
self._send_json({"type": "hwpod-node-ops-accepted", "nodeId": self.executor.node_id, "requestId": request_id, "planId": plan_id, "observedAt": utc_now()})
|
||||
if isinstance(existing, dict) and existing.get("status") == "completed" and isinstance(existing.get("result"), dict):
|
||||
self._send_json({"type": "hwpod-node-ops-result", "nodeId": self.executor.node_id, "requestId": request_id, "result": existing["result"], "observedAt": utc_now()})
|
||||
return
|
||||
ledger[plan_id] = {"status": "accepted", "acceptedAt": utc_now(), "result": None}
|
||||
self._save_operation_ledger(ledger)
|
||||
try:
|
||||
result = self.executor.execute(message.get("plan") or {})
|
||||
result = self.executor.execute(plan)
|
||||
except Exception as exc:
|
||||
result = {"ok": False, "status": "failed", "results": [], "blocker": {"code": "hwpod_node_ws_run_failed", "layer": "hwpod-node", "retryable": True, "summary": str(exc)}}
|
||||
ledger[plan_id] = {"status": "completed", "acceptedAt": ledger[plan_id]["acceptedAt"], "completedAt": utc_now(), "result": result}
|
||||
self._save_operation_ledger(ledger)
|
||||
self._send_json({"type": "hwpod-node-ops-result", "nodeId": self.executor.node_id, "requestId": request_id, "result": result, "observedAt": utc_now()})
|
||||
|
||||
def _operation_ledger(self) -> dict:
|
||||
try:
|
||||
value = json.loads(OPERATION_LEDGER_PATH.read_text(encoding="utf-8"))
|
||||
ledger = value if isinstance(value, dict) else {}
|
||||
except Exception:
|
||||
ledger = {}
|
||||
if self.operation_retention_seconds > 0:
|
||||
cutoff = time.time() - self.operation_retention_seconds
|
||||
ledger = {key: value for key, value in ledger.items() if not isinstance(value, dict) or self._operation_timestamp(value) >= cutoff}
|
||||
return ledger
|
||||
|
||||
def _save_operation_ledger(self, ledger: dict) -> None:
|
||||
atomic_write_json(OPERATION_LEDGER_PATH, ledger)
|
||||
|
||||
def _operation_timestamp(self, value: dict) -> float:
|
||||
timestamp = str(value.get("completedAt") or value.get("acceptedAt") or "")
|
||||
try:
|
||||
return calendar.timegm(time.strptime(timestamp, "%Y-%m-%dT%H:%M:%SZ"))
|
||||
except Exception:
|
||||
return time.time()
|
||||
|
||||
def _flush_diagnostics(self) -> None:
|
||||
for event in DIAGNOSTICS.since(self.diagnostic_cursor, 20):
|
||||
self._send_json({"type": "hwpod-node-diagnostic", "nodeId": self.executor.node_id, "diagnostic": event, "observedAt": utc_now()})
|
||||
|
||||
Reference in New Issue
Block a user