fix:优化wsl环境下的边缘设备执行逻辑
This commit is contained in:
@@ -2,6 +2,7 @@ import asyncio
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from urllib.parse import urlparse
|
||||
@@ -13,6 +14,12 @@ DISPATCH_WS_URL = os.getenv("DISPATCH_WS_URL", "ws://127.0.0.1:8020/ws/edge/edge
|
||||
WORKER_BASE_URL = os.getenv("WORKER_BASE_URL", "http://127.0.0.1:8000")
|
||||
POLL_INTERVAL = float(os.getenv("EDGE_POLL_INTERVAL_SEC", "1.0"))
|
||||
DISPATCH_HTTP_BASE = os.getenv("DISPATCH_HTTP_BASE", "")
|
||||
ALLOW_REMOTE_UPDATE = os.getenv("EDGE_ALLOW_REMOTE_UPDATE", "true").lower() in {"1", "true", "yes", "on"}
|
||||
ALLOW_REMOTE_RESTART = os.getenv("EDGE_ALLOW_REMOTE_RESTART", "true").lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
ROOT_DIR = SCRIPT_DIR.parent
|
||||
RESTART_SCRIPT = ROOT_DIR / "scripts" / "restart_edge_device_local.sh"
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
DISPATCH_WS_URL = sys.argv[1]
|
||||
@@ -41,6 +48,18 @@ def worker_get(path: str):
|
||||
return r.json()
|
||||
|
||||
|
||||
def run_shell(command: str, timeout_sec: int = 1200) -> tuple[int, str, str]:
|
||||
proc = subprocess.run(
|
||||
command,
|
||||
cwd=str(ROOT_DIR),
|
||||
shell=True,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=timeout_sec,
|
||||
)
|
||||
return proc.returncode, proc.stdout.strip(), proc.stderr.strip()
|
||||
|
||||
|
||||
def upload_artifacts(dispatch_id: str, task_id: str, result: dict) -> dict:
|
||||
candidate_fields = ["video_path", "first_frame_path", "metadata_path", "log_path"]
|
||||
existing_paths = []
|
||||
@@ -78,6 +97,12 @@ def upload_artifacts(dispatch_id: str, task_id: str, result: dict) -> dict:
|
||||
fh.close()
|
||||
|
||||
|
||||
def _short_text(text: str, limit: int = 1500) -> str:
|
||||
if len(text) <= limit:
|
||||
return text
|
||||
return text[:limit] + "...(truncated)"
|
||||
|
||||
|
||||
async def handle_generate(ws, data: dict):
|
||||
dispatch_id = data["dispatch_id"]
|
||||
req = data["request"]
|
||||
@@ -114,13 +139,126 @@ async def handle_generate(ws, data: dict):
|
||||
result_payload["artifact_urls"] = artifact_urls
|
||||
else:
|
||||
result_payload["error"] = result.get("error")
|
||||
await ws.send(
|
||||
json.dumps(result_payload, ensure_ascii=False)
|
||||
)
|
||||
await ws.send(json.dumps(result_payload, ensure_ascii=False))
|
||||
return
|
||||
await asyncio.sleep(POLL_INTERVAL)
|
||||
|
||||
|
||||
async def handle_update_code(ws, data: dict):
|
||||
dispatch_id = data.get("dispatch_id", "")
|
||||
if not ALLOW_REMOTE_UPDATE:
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{
|
||||
"event": "command_result",
|
||||
"dispatch_id": dispatch_id,
|
||||
"command": "update_code",
|
||||
"status": "FAILED",
|
||||
"error": "EDGE_ALLOW_REMOTE_UPDATE=false",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
branch = data.get("branch", "master")
|
||||
git_command = data.get("command") or f"git fetch --all && git checkout {branch} && git pull --ff-only origin {branch}"
|
||||
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{"event": "command_status", "dispatch_id": dispatch_id, "command": "update_code", "status": "RUNNING"},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
|
||||
code, out, err = await asyncio.to_thread(run_shell, git_command, 1800)
|
||||
payload = {
|
||||
"event": "command_result",
|
||||
"dispatch_id": dispatch_id,
|
||||
"command": "update_code",
|
||||
"status": "SUCCEEDED" if code == 0 else "FAILED",
|
||||
"exit_code": code,
|
||||
"stdout": _short_text(out),
|
||||
"stderr": _short_text(err),
|
||||
}
|
||||
await ws.send(json.dumps(payload, ensure_ascii=False))
|
||||
|
||||
|
||||
async def handle_restart_service(ws, data: dict):
|
||||
dispatch_id = data.get("dispatch_id", "")
|
||||
if not ALLOW_REMOTE_RESTART:
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{
|
||||
"event": "command_result",
|
||||
"dispatch_id": dispatch_id,
|
||||
"command": "restart_service",
|
||||
"status": "FAILED",
|
||||
"error": "EDGE_ALLOW_REMOTE_RESTART=false",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
if not RESTART_SCRIPT.exists():
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{
|
||||
"event": "command_result",
|
||||
"dispatch_id": dispatch_id,
|
||||
"command": "restart_service",
|
||||
"status": "FAILED",
|
||||
"error": f"restart script missing: {RESTART_SCRIPT}",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{"event": "command_status", "dispatch_id": dispatch_id, "command": "restart_service", "status": "RUNNING"},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{
|
||||
"event": "command_result",
|
||||
"dispatch_id": dispatch_id,
|
||||
"command": "restart_service",
|
||||
"status": "SUCCEEDED",
|
||||
"message": "restart script launched",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
|
||||
subprocess.Popen(
|
||||
["bash", str(RESTART_SCRIPT)],
|
||||
cwd=str(ROOT_DIR),
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
start_new_session=True,
|
||||
)
|
||||
raise SystemExit(0)
|
||||
|
||||
|
||||
async def handle_ping(ws, data: dict):
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{
|
||||
"event": "pong",
|
||||
"dispatch_id": data.get("dispatch_id", ""),
|
||||
"status": "ok",
|
||||
"worker_base_url": WORKER_BASE_URL,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
while True:
|
||||
try:
|
||||
@@ -132,8 +270,16 @@ async def main() -> None:
|
||||
event = data.get("event")
|
||||
if event == "generate":
|
||||
await handle_generate(ws, data)
|
||||
elif event == "update_code":
|
||||
await handle_update_code(ws, data)
|
||||
elif event == "restart_service":
|
||||
await handle_restart_service(ws, data)
|
||||
elif event == "ping":
|
||||
await handle_ping(ws, data)
|
||||
elif event == "registered":
|
||||
print("registered", data)
|
||||
except SystemExit:
|
||||
return
|
||||
except Exception as exc:
|
||||
print("connection error, retry in 3s:", exc)
|
||||
time.sleep(3)
|
||||
|
||||
54
video_worker/scripts/edge_device_wsl.ps1
Normal file
54
video_worker/scripts/edge_device_wsl.ps1
Normal file
@@ -0,0 +1,54 @@
|
||||
param(
|
||||
[ValidateSet("start", "stop", "restart", "status")]
|
||||
[string]$Action = "start",
|
||||
[string]$Distro = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$Root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
Set-Location $Root
|
||||
|
||||
if (!(Get-Command wsl -ErrorAction SilentlyContinue)) {
|
||||
throw "WSL command not found. Please install WSL first."
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Distro)) {
|
||||
$linuxPath = (wsl -- wslpath -a "$Root").Trim()
|
||||
} else {
|
||||
$linuxPath = (wsl -d $Distro -- wslpath -a "$Root").Trim()
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($linuxPath)) {
|
||||
throw "Failed to resolve WSL path for project root: $Root"
|
||||
}
|
||||
|
||||
switch ($Action) {
|
||||
"start" { $targetScript = "scripts/start_edge_device_local.sh" }
|
||||
"stop" { $targetScript = "scripts/stop_edge_device_local.sh" }
|
||||
"restart" { $targetScript = "scripts/restart_edge_device_local.sh" }
|
||||
"status" { $targetScript = "" }
|
||||
}
|
||||
|
||||
if ($Action -eq "status") {
|
||||
$bashCommand = @"
|
||||
cd '$linuxPath' && \
|
||||
if [ -f runtime/pids/worker.pid ] && kill -0 `$(cat runtime/pids/worker.pid) >/dev/null 2>&1; then
|
||||
echo "[OK] worker running pid=`$(cat runtime/pids/worker.pid)"
|
||||
else
|
||||
echo "[INFO] worker not running"
|
||||
fi && \
|
||||
if [ -f runtime/pids/edge_client.pid ] && kill -0 `$(cat runtime/pids/edge_client.pid) >/dev/null 2>&1; then
|
||||
echo "[OK] edge_client running pid=`$(cat runtime/pids/edge_client.pid)"
|
||||
else
|
||||
echo "[INFO] edge_client not running"
|
||||
fi
|
||||
"@
|
||||
} else {
|
||||
$bashCommand = "cd '$linuxPath' && chmod +x scripts/install_wsl_env.sh scripts/start_edge_device_local.sh scripts/stop_edge_device_local.sh scripts/restart_edge_device_local.sh && bash $targetScript"
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($Distro)) {
|
||||
wsl -- bash -lc "$bashCommand"
|
||||
} else {
|
||||
wsl -d $Distro -- bash -lc "$bashCommand"
|
||||
}
|
||||
9
video_worker/scripts/restart_edge_device_local.sh
Normal file
9
video_worker/scripts/restart_edge_device_local.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
bash scripts/stop_edge_device_local.sh
|
||||
sleep 1
|
||||
bash scripts/start_edge_device_local.sh
|
||||
41
video_worker/scripts/stop_edge_device_local.sh
Normal file
41
video_worker/scripts/stop_edge_device_local.sh
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
PID_DIR="runtime/pids"
|
||||
WORKER_PID_FILE="${PID_DIR}/worker.pid"
|
||||
EDGE_CLIENT_PID_FILE="${PID_DIR}/edge_client.pid"
|
||||
|
||||
stop_by_pid_file() {
|
||||
local name="$1"
|
||||
local pid_file="$2"
|
||||
if [ ! -f "$pid_file" ]; then
|
||||
echo "[INFO] ${name} not running (no pid file)"
|
||||
return
|
||||
fi
|
||||
|
||||
local pid
|
||||
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
||||
if [ -z "$pid" ]; then
|
||||
rm -f "$pid_file"
|
||||
echo "[INFO] ${name} pid file empty, cleaned"
|
||||
return
|
||||
fi
|
||||
|
||||
if kill -0 "$pid" >/dev/null 2>&1; then
|
||||
kill "$pid" >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
if kill -0 "$pid" >/dev/null 2>&1; then
|
||||
kill -9 "$pid" >/dev/null 2>&1 || true
|
||||
fi
|
||||
echo "[OK] ${name} stopped (pid ${pid})"
|
||||
else
|
||||
echo "[INFO] ${name} already stopped (stale pid ${pid})"
|
||||
fi
|
||||
rm -f "$pid_file"
|
||||
}
|
||||
|
||||
stop_by_pid_file "edge client" "$EDGE_CLIENT_PID_FILE"
|
||||
stop_by_pid_file "worker" "$WORKER_PID_FILE"
|
||||
Reference in New Issue
Block a user