This commit is contained in:
Your Name
2026-04-17 15:13:46 +08:00
parent fe87c7b343
commit 0e096947fc
19 changed files with 791 additions and 151 deletions

View File

@@ -8,7 +8,7 @@ from app.core.config import settings
from app.services.debug_event_service import push_debug_event
from app.services.sync_push_service import pull_detect_task_batch_now, push_runtime_projection_now
from app.services.runtime_settings_service import get_runtime_settings
from app.services.worker_control_service import _run_systemctl, start_worker, stop_worker
from app.services.worker_control_service import _run_systemctl, normalize_systemctl_error, start_worker, stop_worker
def _workspace_root() -> Path:
@@ -29,7 +29,7 @@ def restart_api() -> tuple[bool, str]:
# blocking the HTTP request until uvicorn is torn down.
result = _run_systemctl(["restart", api_service_name], timeout=5, no_block=True)
if result.returncode != 0:
return False, (result.stderr or result.stdout or "重启 Linux API 失败").strip()
return False, normalize_systemctl_error(result.stderr or result.stdout or "重启 Linux API 失败", service_name=api_service_name)
return True, f"Linux API 重启命令已发送: {api_service_name}"
if os.name != "nt":
@@ -59,7 +59,7 @@ def _run_systemd_action(service_name: str, action: str, *, no_block: bool = Fals
systemctl_command.extend([action, service_name])
result = _run_systemctl(systemctl_command, timeout=10 if no_block else 30)
if result.returncode != 0:
return False, (result.stderr or result.stdout or f"{action} {service_name} 失败").strip()
return False, normalize_systemctl_error(result.stderr or result.stdout or f"{action} {service_name} 失败", service_name=service_name)
return True, f"{service_name} {action} 命令已发送"
@@ -80,6 +80,42 @@ def _emit_runtime_action_event(action: str, *, stage: str, ok: bool, message: st
pass
def _build_runtime_action_result(
*,
action: str,
poll_after_seconds: int,
refresh_runtime: bool,
ok: bool,
message: str,
data: dict | None = None,
) -> dict:
result = {
"action": action,
"poll_after_seconds": poll_after_seconds,
"refresh_runtime": refresh_runtime,
**(data or {}),
}
lowered = str(message or "").strip().lower()
if "ui_level" not in result:
if not ok:
result["ui_level"] = "warning" if any(keyword in lowered for keyword in ("当前没有", "无需", "未启用", "未配置")) else "error"
elif any(keyword in str(message or "") for keyword in ("命令已发送", "确认失败")):
result["ui_level"] = "warning"
else:
result["ui_level"] = "success"
if "poll_schedule_seconds" not in result:
if action in {"start_worker", "stop_worker", "restart_api", "start_sync_agent", "stop_sync_agent"}:
result["poll_schedule_seconds"] = [1, max(2, poll_after_seconds)]
elif action in {"push_sync", "pull_tasks"}:
result["poll_schedule_seconds"] = [1, max(2, poll_after_seconds)]
elif poll_after_seconds > 0:
result["poll_schedule_seconds"] = [poll_after_seconds]
else:
result["poll_schedule_seconds"] = []
return result
def start_sync_agent() -> tuple[bool, str]:
runtime = get_runtime_settings()
worker_mode = runtime.get("worker_mode", settings.worker_mode)
@@ -109,47 +145,37 @@ def runtime_action(action: str) -> tuple[bool, str, dict]:
)
if normalized_action == "start_worker":
ok, message = start_worker()
result = {"action": normalized_action, "poll_after_seconds": 2, "refresh_runtime": True}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=2, refresh_runtime=True, ok=ok, message=message)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
if normalized_action == "stop_worker":
ok, message = stop_worker()
result = {"action": normalized_action, "poll_after_seconds": 2, "refresh_runtime": True}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=2, refresh_runtime=True, ok=ok, message=message)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
if normalized_action == "restart_api":
ok, message = restart_api()
result = {"action": normalized_action, "poll_after_seconds": 4, "refresh_runtime": True}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=4, refresh_runtime=True, ok=ok, message=message)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
if normalized_action == "start_sync_agent":
ok, message = start_sync_agent()
result = {"action": normalized_action, "poll_after_seconds": 2, "refresh_runtime": True}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=2, refresh_runtime=True, ok=ok, message=message)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
if normalized_action == "stop_sync_agent":
ok, message = stop_sync_agent()
result = {"action": normalized_action, "poll_after_seconds": 2, "refresh_runtime": True}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=2, refresh_runtime=True, ok=ok, message=message)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
if normalized_action == "push_sync":
ok, message, data = push_runtime_projection_now()
result = {
"action": normalized_action,
"poll_after_seconds": 2,
"refresh_runtime": True,
**(data or {}),
}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=2, refresh_runtime=True, ok=ok, message=message, data=data)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
if normalized_action == "pull_tasks":
ok, message, data = pull_detect_task_batch_now()
result = {
"action": normalized_action,
"poll_after_seconds": 2,
"refresh_runtime": True,
**(data or {}),
}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=2, refresh_runtime=True, ok=ok, message=message, data=data)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
if normalized_action == "push_debug_probe":
@@ -160,18 +186,9 @@ def runtime_action(action: str) -> tuple[bool, str, dict]:
message="manual debug probe",
payload={"node_code": settings.node_code, "node_region": settings.node_region},
)
result = {
"action": normalized_action,
"poll_after_seconds": 1,
"refresh_runtime": False,
**(data or {}),
}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=1, refresh_runtime=False, ok=ok, message=message, data=data)
_emit_runtime_action_event(normalized_action, stage="finished", ok=ok, message=message, data=result)
return ok, message, result
result = {
"action": normalized_action,
"poll_after_seconds": 0,
"refresh_runtime": False,
}
result = _build_runtime_action_result(action=normalized_action, poll_after_seconds=0, refresh_runtime=False, ok=False, message=f"不支持的运行时动作: {action}")
_emit_runtime_action_event(normalized_action, stage="finished", ok=False, message=f"不支持的运行时动作: {action}", data=result)
return False, f"不支持的运行时动作: {action}", result