feat: 连接 URL 自动拼接设备号并区分连接失败原因
- server.url 作为通道基地址,设备号统一由 device.id 拼接,消除两处配置不一致的可能 - 断线日志区分「网络不通」与「被服务器拒绝(设备未注册/token 错误)」 - 配置文件补充逐项中文注释 - 移除 PID 文件逻辑 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -8,13 +8,11 @@ hospital-agent.exe (PyInstaller 打包后)
|
|||||||
职责:
|
职责:
|
||||||
1. WebSocket 主动连接 B 端管理服务器(注册/心跳/命令)
|
1. WebSocket 主动连接 B 端管理服务器(注册/心跳/命令)
|
||||||
2. 守护主程序(健康探测 + 宕机拉起)
|
2. 守护主程序(健康探测 + 宕机拉起)
|
||||||
3. 写 PID 文件(pid/hospital-agent.pid)
|
|
||||||
|
|
||||||
由 WinSW/NSSM Windows 服务守护本进程。
|
由 WinSW/NSSM Windows 服务守护本进程。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
@@ -43,9 +41,6 @@ def run():
|
|||||||
config = AgentConfig.load()
|
config = AgentConfig.load()
|
||||||
log.info("Agent 启动:deviceId=%s, server=%s", config.device_id, config.server_url)
|
log.info("Agent 启动:deviceId=%s, server=%s", config.device_id, config.server_url)
|
||||||
|
|
||||||
# 写 PID 文件
|
|
||||||
_write_pid_file()
|
|
||||||
|
|
||||||
# 组装组件(延迟导入避免环)
|
# 组装组件(延迟导入避免环)
|
||||||
from agent.dispatcher import CommandDispatcher
|
from agent.dispatcher import CommandDispatcher
|
||||||
from agent.process_guard import ProcessGuard
|
from agent.process_guard import ProcessGuard
|
||||||
@@ -81,15 +76,5 @@ def _shutdown(signum, frame):
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
def _write_pid_file():
|
|
||||||
"""写 PID 文件(pid/hospital-agent.pid)。"""
|
|
||||||
try:
|
|
||||||
os.makedirs("pid", exist_ok=True)
|
|
||||||
with open(os.path.join("pid", "hospital-agent.pid"), "w", encoding="utf-8") as f:
|
|
||||||
f.write(str(os.getpid()))
|
|
||||||
except Exception as e:
|
|
||||||
log.warning("PID 文件写入失败:%s", e)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
run()
|
||||||
|
|||||||
+10
-3
@@ -58,7 +58,8 @@ class AgentClient:
|
|||||||
|
|
||||||
def _connect(self):
|
def _connect(self):
|
||||||
"""建立 WebSocket 连接(阻塞直到连接断开,内部自行调度重连)。"""
|
"""建立 WebSocket 连接(阻塞直到连接断开,内部自行调度重连)。"""
|
||||||
url = self.config.server_url
|
# server.url 为通道基地址(以 /medical/agentSocket/ 结尾),设备号统一由 device.id 拼接
|
||||||
|
url = self.config.server_url.rstrip("/") + "/" + self.config.device_id
|
||||||
log.info("连接管理服务器:%s", url)
|
log.info("连接管理服务器:%s", url)
|
||||||
|
|
||||||
headers = [
|
headers = [
|
||||||
@@ -86,12 +87,18 @@ class AgentClient:
|
|||||||
|
|
||||||
def on_close(ws, code, reason):
|
def on_close(ws, code, reason):
|
||||||
self._connected = False
|
self._connected = False
|
||||||
log.info("连接关闭:code=%s, reason=%s", code, reason)
|
# 区分失败类型:1000/1001 为正常关闭;其他关闭码(如 1008 策略拒绝)多为设备未注册或 token 错误
|
||||||
|
if code in (1000, 1001):
|
||||||
|
log.info("连接关闭:code=%s, reason=%s", code, reason)
|
||||||
|
elif reason:
|
||||||
|
log.warning("连接被服务器拒绝(设备未注册或 token 错误):code=%s, reason=%s", code, reason)
|
||||||
|
else:
|
||||||
|
log.warning("连接被服务器关闭:code=%s(设备未注册或 token 错误)", code)
|
||||||
self._schedule_reconnect()
|
self._schedule_reconnect()
|
||||||
|
|
||||||
def on_error(ws, error):
|
def on_error(ws, error):
|
||||||
self._connected = False
|
self._connected = False
|
||||||
log.warning("连接失败:%s,将重连", error)
|
log.warning("网络不通(无法连接管理服务器):%s,将重连", error)
|
||||||
# websocket-client 出错后必定回调 on_close,重连由 on_close 统一调度
|
# websocket-client 出错后必定回调 on_close,重连由 on_close 统一调度
|
||||||
# 此处不重复调度,避免双重重连
|
# 此处不重复调度,避免双重重连
|
||||||
|
|
||||||
|
|||||||
+34
-8
@@ -1,13 +1,39 @@
|
|||||||
# Agent 配置
|
# ============================================================
|
||||||
# 值优先从环境变量读取(AGENT_ 前缀 + 大写 + 下划线,如 AGENT_SERVER_URL)
|
# Agent \u914D\u7F6E\u6587\u4EF6
|
||||||
# 服务脚本自动加载 conf/.env 设置环境变量;NSSM 用 AppEnvironmentExtra 设置
|
# \u8BFB\u53D6\u4F18\u5148\u7EA7\uFF1A\u73AF\u5883\u53D8\u91CF\uFF08AGENT_ \u524D\u7F00 + \u5927\u5199 + \u4E0B\u5212\u7EBF\uFF0C\u5982 AGENT_SERVER_URL\uFF09
|
||||||
#
|
# > \u672C\u6587\u4EF6 > \u4EE3\u7801\u5185\u7F6E\u9ED8\u8BA4\u503C
|
||||||
# 以下是 fallback 默认值(环境变量未设置时使用):
|
# \u670D\u52A1\u811A\u672C\u81EA\u52A8\u52A0\u8F7D conf/.env \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\uFF1BNSSM \u7528 AppEnvironmentExtra \u8BBE\u7F6E
|
||||||
server.url=ws://10.10.10.228:19901/medical/agentSocket/unknown-device
|
# ============================================================
|
||||||
device.id=unknown-device
|
|
||||||
device.token=
|
# B \u7AEF\u7BA1\u7406\u670D\u52A1\u5668 WebSocket \u901A\u9053\u57FA\u5730\u5740\uFF08\u7ECF\u7F51\u5173\u8F6C\u53D1\uFF0C\u987B\u5E26 /medical \u670D\u52A1\u524D\u7F00\uFF0C\u4EE5 /agentSocket/ \u7ED3\u5C3E\uFF09
|
||||||
|
# \u6CE8\u610F\uFF1A\u8BBE\u5907\u53F7\u4E0D\u5199\u5728\u8FD9\u91CC\uFF0C\u8FDE\u63A5\u65F6\u81EA\u52A8\u62FC\u63A5 device.id
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_SERVER_URL
|
||||||
|
server.url=ws://10.10.10.228:19901/medical/agentSocket/
|
||||||
|
|
||||||
|
# \u8BBE\u5907\u7F16\u53F7\uFF08\u533B\u9662\u552F\u4E00\uFF0C\u5982 jinghe-01\uFF0C\u9700\u5148\u5728 B \u7AEF\u6CE8\u518C\uFF0C\u5426\u5219\u8FDE\u63A5\u4F1A\u88AB\u62D2\u7EDD\uFF09
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_DEVICE_ID
|
||||||
|
device.id=jinghe-01
|
||||||
|
|
||||||
|
# \u8BBE\u5907\u9274\u6743 Token\uFF08B \u7AEF\u6CE8\u518C\u8BBE\u5907\u65F6\u4E0B\u53D1\uFF0C\u4E3A\u7A7A\u5219\u4E0D\u643A\u5E26\uFF09
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_DEVICE_TOKEN
|
||||||
|
device.token=dccbd1eca07511f181d5a0369fe0bc61
|
||||||
|
|
||||||
|
# \u4E3B\u7A0B\u5E8F\u5065\u5EB7\u68C0\u67E5\u5730\u5740\uFF08\u770B\u95E8\u72D7\u6309\u6B64\u5730\u5740\u63A2\u6D4B\u4E3B\u7A0B\u5E8F\u662F\u5426\u5B58\u6D3B\uFF09
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_MAIN_HEALTH_URL
|
||||||
main.health.url=http://127.0.0.1:8082/api/admin/health
|
main.health.url=http://127.0.0.1:8082/api/admin/health
|
||||||
|
|
||||||
|
# \u4E3B\u7A0B\u5E8F\u7BA1\u7406\u63A5\u53E3 Token\uFF08\u987B\u4E0E\u4E3B\u7A0B\u5E8F\u914D\u7F6E\u4E2D\u7684 admin.token \u4E00\u81F4\uFF0C\u73AF\u56DE\u8C03\u7528 /api/admin \u65F6\u9274\u6743\u7528\uFF09
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_MAIN_ADMIN_TOKEN
|
||||||
main.admin.token=
|
main.admin.token=
|
||||||
|
|
||||||
|
# \u4E3B\u7A0B\u5E8F\u542F\u52A8\u547D\u4EE4\uFF08\u770B\u95E8\u72D7\u68C0\u6D4B\u5230\u4E3B\u7A0B\u5E8F\u5B95\u673A\u540E\u6267\u884C\u6B64\u547D\u4EE4\u62C9\u8D77\uFF09
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_MAIN_START_CMD
|
||||||
main.start.cmd=bin/service.bat main start
|
main.start.cmd=bin/service.bat main start
|
||||||
|
|
||||||
|
# \u5FC3\u8DF3\u95F4\u9694\uFF0C\u5355\u4F4D\u79D2\uFF08\u9ED8\u8BA4 15\uFF0C\u987B\u5C0F\u4E8E\u7F51\u5173\u7A7A\u95F2\u8D85\u65F6\uFF0C\u5426\u5219\u8FDE\u63A5\u4F1A\u88AB\u7F51\u5173\u65AD\u5F00\uFF09
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_HEARTBEAT_SEC
|
||||||
heartbeat.sec=15
|
heartbeat.sec=15
|
||||||
|
|
||||||
|
# \u662F\u5426\u542F\u7528\u770B\u95E8\u72D7\u5B88\u62A4\u4E3B\u7A0B\u5E8F\uFF08true/false\uFF0C\u9ED8\u8BA4 true\uFF1Bfalse \u65F6\u4EC5\u505A\u8FD0\u7EF4\u547D\u4EE4\u901A\u9053\uFF09
|
||||||
|
# \u5BF9\u5E94\u73AF\u5883\u53D8\u91CF\uFF1AAGENT_GUARD_ENABLE
|
||||||
guard.enable=true
|
guard.enable=true
|
||||||
|
|||||||
Reference in New Issue
Block a user