diff --git a/README.md b/README.md index 870a382..291287a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,6 @@ http_url TEXT NOT NULL, ws_url TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'offline', - last_heartbeat DATETIME, last_health_check DATETIME, current_tasks INTEGER DEFAULT 0, max_concurrent_tasks INTEGER DEFAULT 1, @@ -127,7 +126,6 @@ ComfyUI 服务器管理器现在支持持久化功能,这意味着即使管理 - **自动持久化**: 服务器注册、状态变化、注销时自动保存到数据库 - **自动恢复**: 服务启动时自动从数据库加载已注册的服务器 - **健康检查**: 定期检查服务器健康状态并更新数据库 -- **心跳机制**: 支持服务器主动发送心跳,自动检测超时 ## 使用方法 diff --git a/js/publisher.js b/js/publisher.js index bff598f..ca1e763 100644 --- a/js/publisher.js +++ b/js/publisher.js @@ -1,413 +1,44 @@ import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; -// 检测ComfyUI服务端口的函数 -async function detectComfyUIPort(host) { - try { - const currentPort = window.location.port; - if (currentPort) { - console.log(`从当前页面URL获取端口: ${currentPort}`); - return parseInt(currentPort); - } - } catch (error) { - console.warn("无法从当前页面获取端口:", error); - } - - // 默认返回8188 - console.warn("无法检测到ComfyUI端口,使用默认端口8188"); - return 8188; -} - -// 获取本地IP地址的函数 -async function getLocalIPAddress() { - try { - // 尝试通过WebRTC获取本地IP地址 - const pc = new RTCPeerConnection({ - iceServers: [], - }); - - pc.createDataChannel(""); - const offer = await pc.createOffer(); - await pc.setLocalDescription(offer); - - return new Promise((resolve) => { - pc.onicecandidate = (event) => { - if (event.candidate) { - const ipMatch = event.candidate.candidate.match( - /([0-9]{1,3}(\.[0-9]{1,3}){3})/ - ); - if (ipMatch) { - const localIP = ipMatch[1]; - // 保留有效的内网IP地址 - if ( - localIP.startsWith("192.168.") || - localIP.startsWith("10.") || - localIP.startsWith("172.") || - localIP === "127.0.0.1" - ) { - pc.close(); - resolve(localIP); - } - } - } - }; - - // 超时处理 - setTimeout(() => { - pc.close(); - resolve("127.0.0.1"); // 如果获取失败,使用默认地址 - }, 3000); - }); - } catch (error) { - console.warn("无法获取本地IP地址,使用默认地址:", error); - return "127.0.0.1"; - } -} - // 本地存储的 key -const COMFY_SERVER_REGISTRATION_KEY = "comfyui_server_registration"; +const WORKFLOW_SERVICE_HOST_KEY = "workflow_publisher_service_host"; -// ComfyUI服务器注册配置 - 使用动态IP地址 -let DEFAULT_SERVER_CONFIG = { - name: "comfyui_node_1", - http_url: "http://127.0.0.1:8188", // 将在初始化时更新为实际IP - workflow_service_host: "http://localhost:8000", -}; +// 默认工作流服务地址 +const DEFAULT_WORKFLOW_SERVICE_HOST = "http://localhost:8000"; -// 初始化默认配置 -async function initializeDefaultConfig() { +// 获取工作流服务地址 +function getWorkflowServiceHost() { try { - const localIP = await getLocalIPAddress(); - const port = await detectComfyUIPort(localIP); - DEFAULT_SERVER_CONFIG.http_url = `http://${localIP}:${port}`; - console.log("自动获取本地IP地址和端口:", localIP, port); + const stored = localStorage.getItem(WORKFLOW_SERVICE_HOST_KEY); + return stored || DEFAULT_WORKFLOW_SERVICE_HOST; } catch (error) { - console.warn("初始化IP地址和端口失败,使用默认地址:", error); + console.error("读取工作流服务地址失败:", error); + return DEFAULT_WORKFLOW_SERVICE_HOST; } } -// 获取ComfyUI服务器注册配置 -function getComfyServerConfig() { +// 保存工作流服务地址 +function saveWorkflowServiceHost(host) { try { - const stored = localStorage.getItem(COMFY_SERVER_REGISTRATION_KEY); - return stored ? JSON.parse(stored) : { ...DEFAULT_SERVER_CONFIG }; + localStorage.setItem(WORKFLOW_SERVICE_HOST_KEY, host); } catch (error) { - console.error("读取ComfyUI服务器配置失败:", error); - return { ...DEFAULT_SERVER_CONFIG }; + console.error("保存工作流服务地址失败:", error); } } -// 保存ComfyUI服务器注册配置 -function saveComfyServerConfig(config) { - try { - localStorage.setItem(COMFY_SERVER_REGISTRATION_KEY, JSON.stringify(config)); - } catch (error) { - console.error("保存ComfyUI服务器配置失败:", error); - } -} - -// 获取本地设置 -function getLocalSettings() { - try { - const stored = localStorage.getItem("workflow_publisher_settings"); - return stored ? JSON.parse(stored) : { host: "" }; - } catch (error) { - console.error("读取本地设置失败:", error); - return { host: "" }; - } -} - -// 保存本地设置 -function saveLocalSettings(settings) { - try { - localStorage.setItem( - "workflow_publisher_settings", - JSON.stringify(settings) - ); - } catch (error) { - console.error("保存本地设置失败:", error); - } -} - -// ComfyUI服务器注册管理器 -class ComfyServerManager { - constructor() { - this.registrationInterval = null; - this.heartbeatInterval = null; - this.isRegistered = false; - this.serverConfig = getComfyServerConfig(); - } - - // 注册服务器到工作流服务 - async registerServer() { - if (!this.serverConfig.workflow_service_host) { - return { success: false, error: "未设置工作流服务地址" }; - } - - try { - const response = await fetch( - `${this.serverConfig.workflow_service_host}/api/comfy/register`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - name: this.serverConfig.name, - http_url: this.serverConfig.http_url, - ws_url: this.getWebSocketUrl(), - }), - } - ); - - if (response.ok) { - const result = await response.json(); - console.log("ComfyUI服务器注册成功:", result); - this.isRegistered = true; - this.startHeartbeat(); - return { success: true }; - } else { - const errorText = await response.text(); - const errorMessage = `HTTP ${response.status}: ${ - errorText || "服务器响应错误" - }`; - console.error("ComfyUI服务器注册失败:", errorMessage); - return { success: false, error: errorMessage }; - } - } catch (error) { - const errorMessage = `网络错误: ${error.message}`; - console.error("注册ComfyUI服务器时发生错误:", errorMessage); - return { success: false, error: errorMessage }; - } - } - - // 注销服务器 - async unregisterServer() { - if (!this.serverConfig.workflow_service_host || !this.isRegistered) { - return { success: false, error: "未设置工作流服务地址或服务器未注册" }; - } - - try { - const response = await fetch( - `${this.serverConfig.workflow_service_host}/api/comfy/unregister`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ name: this.serverConfig.name }), - } - ); - - if (response.ok) { - console.log("ComfyUI服务器注销成功"); - this.isRegistered = false; - this.stopHeartbeat(); - return { success: true }; - } else { - const errorText = await response.text(); - const errorMessage = `HTTP ${response.status}: ${ - errorText || "服务器响应错误" - }`; - console.error("ComfyUI服务器注销失败:", errorMessage); - return { success: false, error: errorMessage }; - } - } catch (error) { - const errorMessage = `网络错误: ${error.message}`; - console.error("注销ComfyUI服务器时发生错误:", errorMessage); - return { success: false, error: errorMessage }; - } - } - - // 发送心跳 - async sendHeartbeat() { - if (!this.serverConfig.workflow_service_host || !this.isRegistered) { - return false; - } - - try { - const response = await fetch( - `${this.serverConfig.workflow_service_host}/api/comfy/heartbeat`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ name: this.serverConfig.name }), - } - ); - - if (response.ok) { - console.debug("心跳发送成功"); - return true; - } else { - console.warn("心跳发送失败:", response.status); - // 如果心跳失败,尝试重新注册 - if (response.status === 404) { - console.log("服务器不存在,尝试重新注册..."); - this.isRegistered = false; - await this.registerServer(); - } - return false; - } - } catch (error) { - console.error("发送心跳时发生错误:", error); - // 如果网络错误,尝试重新注册 - this.isRegistered = false; - await this.registerServer(); - return false; - } - } - - // 启动心跳 - startHeartbeat() { - if (this.heartbeatInterval) { - clearInterval(this.heartbeatInterval); - } - - // 每30秒发送一次心跳 - this.heartbeatInterval = setInterval(() => { - this.sendHeartbeat(); - }, 30000); - - console.log("ComfyUI服务器心跳已启动"); - } - - // 停止心跳 - stopHeartbeat() { - if (this.heartbeatInterval) { - clearInterval(this.heartbeatInterval); - this.heartbeatInterval = null; - } - console.log("ComfyUI服务器心跳已停止"); - } - - // 更新服务器配置 - updateConfig(newConfig) { - this.serverConfig = { ...this.serverConfig, ...newConfig }; - saveComfyServerConfig(this.serverConfig); - - // 如果已注册,需要重新注册以更新配置 - if (this.isRegistered) { - this.unregisterServer().then((result) => { - if (result.success) { - setTimeout(() => this.registerServer(), 1000); - } else { - console.warn("更新配置时注销失败:", result.error); - } - }); - } - } - - // 设置工作流服务地址 - setWorkflowServiceHost(host) { - this.serverConfig.workflow_service_host = host; - saveComfyServerConfig(this.serverConfig); - } - - // 获取WebSocket URL(自动从HTTP URL生成) - getWebSocketUrl() { - if (!this.serverConfig.http_url) return ""; - const url = new URL(this.serverConfig.http_url); - // 根据协议自动选择ws或wss - const protocol = url.protocol === "https:" ? "wss:" : "ws:"; - return `${protocol}//${url.host}/ws`; - } - - // 获取服务器状态 - async getServerStatus() { - if (!this.serverConfig.workflow_service_host) { - return null; - } - - try { - const response = await fetch( - `${this.serverConfig.workflow_service_host}/api/comfy/status/${this.serverConfig.name}` - ); - if (response.ok) { - return await response.json(); - } - } catch (error) { - console.error("获取服务器状态失败:", error); - } - return null; - } - - // 获取系统健康状态 - async getSystemHealth() { - if (!this.serverConfig.workflow_service_host) { - return null; - } - - try { - const response = await fetch( - `${this.serverConfig.workflow_service_host}/api/comfy/health` - ); - if (response.ok) { - return await response.json(); - } - } catch (error) { - console.error("获取系统健康状态失败:", error); - } - return null; - } - - // 动态更新IP地址和端口 - async updateLocalIPAddress() { - try { - const localIP = await getLocalIPAddress(); - const port = await detectComfyUIPort(localIP); - const newHttpUrl = `http://${localIP}:${port}`; - - if (this.serverConfig.http_url !== newHttpUrl) { - this.serverConfig.http_url = newHttpUrl; - saveComfyServerConfig(this.serverConfig); - console.log("已更新本地IP地址和端口:", localIP, port); - return { ip: localIP, port: port }; - } - return null; - } catch (error) { - console.warn("更新IP地址和端口失败:", error); - return null; - } - } - - // 同步注册状态 - syncRegistrationStatus() { - if (this.serverConfig.workflow_service_host) { - this.getServerStatus() - .then((status) => { - if (status) { - this.isRegistered = true; - console.log("同步注册状态: 已注册"); - } else { - this.isRegistered = false; - console.log("同步注册状态: 未注册"); - } - }) - .catch((error) => { - console.warn("同步注册状态失败:", error); - this.isRegistered = false; - }); - } - } -} - -// 自定义 fetchApi 函数,使用ComfyUI服务器配置中的工作流服务地址 +// 自定义 fetchApi 函数,使用配置的工作流服务地址 async function customFetchApi(endpoint, options = {}) { try { - // 从ComfyUI服务器配置获取工作流服务地址 - const serverConfig = getComfyServerConfig(); - - // 如果没有配置工作流服务地址,回退到默认的 api.fetchApi - if (!serverConfig.workflow_service_host) { + const host = getWorkflowServiceHost(); + if (!host) { console.warn("未配置工作流服务地址,使用默认的 ComfyUI API"); return await api.fetchApi(endpoint, options); } // 构建完整的 URL - const host = serverConfig.workflow_service_host.replace(/\/$/, ""); // 移除末尾的斜杠 - const fullUrl = `${host}${endpoint}`; + const fullHost = host.replace(/\/$/, ""); // 移除末尾的斜杠 + const fullUrl = `${fullHost}${endpoint}`; console.log(`使用工作流服务地址请求: ${fullUrl}`); @@ -457,7 +88,7 @@ function createElement(tagName, props) { return element; } -// Modal class (保持不变) +// Modal class class Modal { constructor(id, title, full_width = false) { this.id = id; @@ -502,9 +133,6 @@ const createButton = (innerHTML, title, { onClick }) => { app.registerExtension({ name: "Comfy.WorkflowPublisher", async setup() { - // 初始化默认配置,获取本地IP地址 - await initializeDefaultConfig(); - const addCustomStyles = () => { const styleId = "jags-publisher-styles"; if (document.getElementById(styleId)) return; @@ -552,21 +180,22 @@ app.registerExtension({ const iconGet = ``; const iconPublish = ``; + const iconSettings = ``; + const btnGet = createButton(iconGet, "从服务器获取工作流", { onClick: () => showWorkflowListDialog(), }); const btnPublish = createButton(iconPublish, "发布当前工作流", { onClick: () => showPublishDialog(), }); - - const btnComfyServer = createButton(`🖥️`, "ComfyUI服务器管理", { - onClick: () => showComfyServerDialog(), + const btnSettings = createButton(iconSettings, "设置工作流服务地址", { + onClick: () => showSettingsDialog(), }); const separator = document.createElement("div"); separator.style.cssText = "border-left: 1px solid var(--border-color); height: 22px; margin: 0 4px;"; - container.append(btnGet, btnPublish, btnComfyServer, separator); + container.append(btnGet, btnPublish, btnSettings, separator); menu.insertBefore(container, menu.firstChild); }); @@ -581,10 +210,9 @@ app.registerExtension({ true ); - const comfyServerDialog = new Modal( - "comfy-server-dialog", - "ComfyUI服务器管理", - true + const settingsDialog = new Modal( + "workflow-publisher-settings-dialog", + "设置工作流服务地址" ); async function showWorkflowListDialog() { @@ -708,297 +336,93 @@ app.registerExtension({ } } - // ComfyUI 服务器管理对话框 - async function showComfyServerDialog() { + // 设置对话框 + async function showSettingsDialog() { try { - const serverConfig = getComfyServerConfig(); - const settings = getLocalSettings(); + const currentHost = getWorkflowServiceHost(); - // 创建服务器配置表单 - const configForm = ` + const settingsForm = `
- - + + + 这是用于获取和发布工作流的服务地址
-
- - - WebSocket地址将自动生成为: ${ - serverConfig.http_url - ? serverConfig.http_url.replace(/^https?:\/\//, "ws://") + - "/ws" - : "" - } +
+ 连接状态: 未测试
- - -
- - -
- -
- 服务器状态: 未连接 -
- -
- - - - +
+ +
`; - comfyServerDialog.setContent(configForm); - comfyServerDialog.addButtons([ - { label: "关闭", callback: () => comfyServerDialog.hide() }, + settingsDialog.setContent(settingsForm); + settingsDialog.addButtons([ + { label: "关闭", callback: () => settingsDialog.hide() }, ]); - comfyServerDialog.show(); - - // 初始化 ComfyServerManager - const serverManager = new ComfyServerManager(); - if (settings.host) { - serverManager.setWorkflowServiceHost(settings.host); - // 同步注册状态 - serverManager.syncRegistrationStatus(); - } + settingsDialog.show(); // 绑定事件 - const btnRegister = document.getElementById("btn-register"); - const btnUnregister = document.getElementById("btn-unregister"); - const btnRefreshStatus = document.getElementById("btn-refresh-status"); - const btnRefreshIP = document.getElementById("btn-refresh-ip"); + const btnTestConnection = document.getElementById( + "btn-test-connection" + ); + const btnSaveSettings = document.getElementById("btn-save-settings"); const statusText = document.getElementById("status-text"); + const hostInput = document.getElementById("workflow-service-host"); - // 添加HTTP地址输入框的实时预览功能 - const httpUrlInput = document.getElementById("server-http-url"); - const wsUrlPreview = document.getElementById("ws-url-preview"); - - httpUrlInput.addEventListener("input", function () { - const httpUrl = this.value; - if (httpUrl) { - try { - const url = new URL(httpUrl); - // 根据协议自动选择ws或wss - const protocol = url.protocol === "https:" ? "wss:" : "ws:"; - const wsUrl = `${protocol}//${url.host}/ws`; - wsUrlPreview.textContent = wsUrl; - } catch (error) { - wsUrlPreview.textContent = "无效的URL格式"; - } - } else { - wsUrlPreview.textContent = ""; - } - }); - - // 注册服务器 - btnRegister.onclick = async () => { - const newConfig = { - name: document.getElementById("server-name").value, - http_url: document.getElementById("server-http-url").value, - }; - - const workflowHost = document.getElementById( - "workflow-service-host" - ).value; - if (workflowHost) { - serverManager.setWorkflowServiceHost(workflowHost); - // 保存到本地设置 - saveLocalSettings({ host: workflowHost }); - } - - serverManager.updateConfig(newConfig); - - btnRegister.disabled = true; - btnRegister.textContent = "注册中..."; - - const result = await serverManager.registerServer(); - if (result.success) { - statusText.textContent = "已注册"; - statusText.style.color = "var(--success-color)"; - btnRegister.textContent = "已注册"; - btnRegister.disabled = true; - btnUnregister.disabled = false; - } else { - const errorMessage = result.error || "未知错误"; - statusText.textContent = `注册失败: ${errorMessage}`; - statusText.style.color = "var(--error-color)"; - btnRegister.textContent = "注册服务器"; - btnRegister.disabled = false; - } - }; - - // 注销服务器 - btnUnregister.onclick = async () => { - btnUnregister.disabled = true; - btnUnregister.textContent = "注销中..."; - - const result = await serverManager.unregisterServer(); - if (result.success) { - statusText.textContent = "已注销"; - statusText.style.color = "orange"; - btnRegister.disabled = false; - btnRegister.textContent = "注册服务器"; - btnUnregister.disabled = true; - btnUnregister.textContent = "注销服务器"; - } else { - const errorMessage = result.error || "未知错误"; - statusText.textContent = `注销失败: ${errorMessage}`; - statusText.style.color = "var(--error-color)"; - btnUnregister.disabled = false; - btnUnregister.textContent = "注销服务器"; - } - }; - - // 刷新状态 - btnRefreshStatus.onclick = async () => { - if (settings.host) { - serverManager.setWorkflowServiceHost(settings.host); - const status = await serverManager.getServerStatus(); - - // 调试信息 - console.log("服务器状态:", status); - if (status && status.last_heartbeat) { - console.log("最后心跳时间原始值:", status.last_heartbeat); - console.log("时间类型:", typeof status.last_heartbeat); - } - - if (status) { - // 安全地处理时间显示 - let heartbeatTime = "未知"; - if (status.last_heartbeat) { - try { - // 尝试解析ISO格式的时间字符串 - const date = new Date(status.last_heartbeat); - if (!isNaN(date.getTime())) { - heartbeatTime = date.toLocaleString("zh-CN", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - }); - } else { - heartbeatTime = "时间格式错误"; - } - } catch (error) { - console.warn( - "时间解析失败:", - error, - "原始时间:", - status.last_heartbeat - ); - heartbeatTime = "时间解析失败"; - } - } - - statusText.textContent = `在线 - 最后心跳: ${heartbeatTime}`; - statusText.style.color = "var(--success-color)"; - // 同步更新本地注册状态 - serverManager.isRegistered = true; - btnRegister.disabled = true; - btnRegister.textContent = "已注册"; - btnUnregister.disabled = false; - } else { - statusText.textContent = "未注册"; - statusText.style.color = "orange"; - // 同步更新本地注册状态 - serverManager.isRegistered = false; - btnRegister.disabled = false; - btnRegister.textContent = "注册服务器"; - btnUnregister.disabled = true; - } - } - }; - - // 刷新IP地址和端口 - btnRefreshIP.onclick = async () => { - btnRefreshIP.disabled = true; - btnRefreshIP.textContent = "刷新中..."; + // 测试连接 + btnTestConnection.onclick = async () => { + btnTestConnection.disabled = true; + btnTestConnection.textContent = "测试中..."; + statusText.textContent = "正在测试连接..."; + statusText.style.color = "orange"; try { - const result = await serverManager.updateLocalIPAddress(); - if (result) { - // 更新输入框显示 - document.getElementById( - "server-http-url" - ).value = `http://${result.ip}:${result.port}`; - // 更新WebSocket预览 - const wsUrlPreview = document.getElementById("ws-url-preview"); - wsUrlPreview.textContent = `ws://${result.ip}:${result.port}/ws`; + const testHost = hostInput.value.trim(); + if (!testHost) { + throw new Error("请输入工作流服务地址"); + } - statusText.textContent = `IP地址和端口已更新为: ${result.ip}:${result.port}`; + const response = await fetch(`${testHost}/api/workflow`); + if (response.ok) { + statusText.textContent = "连接成功"; statusText.style.color = "var(--success-color)"; } else { - statusText.textContent = "IP地址和端口无需更新"; - statusText.style.color = "orange"; - } - } catch (error) { - statusText.textContent = `IP地址和端口更新失败: ${error.message}`; - statusText.style.color = "var(--error-color)"; - } finally { - btnRefreshIP.disabled = false; - btnRefreshIP.textContent = "刷新IP和端口"; - } - }; - - // 初始状态检查 - if (settings.host) { - btnRefreshStatus.click(); - } else { - // 如果没有设置工作流服务地址,确保按钮状态正确 - btnRegister.disabled = false; - btnUnregister.disabled = true; - } - - // 自动刷新IP地址和端口 - setTimeout(async () => { - try { - const result = await serverManager.updateLocalIPAddress(); - if (result) { - // 更新输入框显示 - document.getElementById( - "server-http-url" - ).value = `http://${result.ip}:${result.port}`; - // 更新WebSocket预览 - const wsUrlPreview = document.getElementById("ws-url-preview"); - wsUrlPreview.textContent = `ws://${result.ip}:${result.port}/ws`; - console.log( - "对话框显示时自动更新IP地址和端口:", - result.ip, - result.port + throw new Error( + `HTTP ${response.status}: ${response.statusText}` ); } } catch (error) { - console.warn("自动更新IP地址和端口失败:", error); + statusText.textContent = `连接失败: ${error.message}`; + statusText.style.color = "var(--error-color)"; + } finally { + btnTestConnection.disabled = false; + btnTestConnection.textContent = "测试连接"; } - }, 500); + }; - // 延迟同步按钮状态,确保与内部状态一致 - setTimeout(() => { - if (serverManager.isRegistered) { - btnRegister.disabled = true; - btnRegister.textContent = "已注册"; - btnUnregister.disabled = false; - } else { - btnRegister.disabled = false; - btnRegister.textContent = "注册服务器"; - btnUnregister.disabled = true; + // 保存设置 + btnSaveSettings.onclick = () => { + const newHost = hostInput.value.trim(); + if (!newHost) { + alert("请输入工作流服务地址"); + return; } - }, 1000); + + saveWorkflowServiceHost(newHost); + statusText.textContent = "设置已保存"; + statusText.style.color = "var(--success-color)"; + + setTimeout(() => { + settingsDialog.hide(); + }, 1000); + }; } catch (error) { - console.error("显示ComfyUI服务器管理对话框失败:", error); + console.error("显示设置对话框失败:", error); alert(`显示对话框失败: ${error.message}`); } } diff --git a/workflow_service/comfy/comfy_server.py b/workflow_service/comfy/comfy_server.py index 6d060b2..82ff26d 100644 --- a/workflow_service/comfy/comfy_server.py +++ b/workflow_service/comfy/comfy_server.py @@ -36,7 +36,6 @@ class ComfyUIServerInfo: http_url: str ws_url: str status: ServerStatus = ServerStatus.OFFLINE - last_heartbeat: Optional[datetime] = None last_health_check: Optional[datetime] = None current_tasks: int = 0 max_concurrent_tasks: int = 1 @@ -60,7 +59,6 @@ class ComfyUIServerInfo: http_url=model.http_url, ws_url=model.ws_url, status=ServerStatus(model.status), - last_heartbeat=model.last_heartbeat, last_health_check=model.last_health_check, current_tasks=model.current_tasks, max_concurrent_tasks=model.max_concurrent_tasks, @@ -75,7 +73,6 @@ class ComfyUIServerInfo: http_url=self.http_url, ws_url=self.ws_url, status=self.status.value, - last_heartbeat=self.last_heartbeat, last_health_check=self.last_health_check, current_tasks=self.current_tasks, max_concurrent_tasks=self.max_concurrent_tasks, @@ -91,7 +88,6 @@ class ComfyUIServerManager: self.servers: Dict[str, ComfyUIServerInfo] = {} # name -> server_info self.lock = asyncio.Lock() self.health_check_interval = 30 # 健康检查间隔(秒) - self.heartbeat_timeout = 60 # 心跳超时时间(秒) self._health_check_task: Optional[asyncio.Task] = None self._initialized = False @@ -145,7 +141,6 @@ class ComfyUIServerManager: http_url=server.http_url, ws_url=server.ws_url, status=server.status.value, - last_heartbeat=server.last_heartbeat, last_health_check=server.last_health_check, current_tasks=server.current_tasks, max_concurrent_tasks=server.max_concurrent_tasks, @@ -238,7 +233,6 @@ class ComfyUIServerManager: if await self._check_server_health(server_info): server_info.status = ServerStatus.ONLINE server_info.last_health_check = datetime.now() - server_info.last_heartbeat = datetime.now() self.servers[name] = server_info @@ -263,17 +257,6 @@ class ComfyUIServerManager: return True return False - async def update_server_heartbeat(self, name: str) -> bool: - """更新服务器心跳""" - async with self.lock: - if name in self.servers: - self.servers[name].last_heartbeat = datetime.now() - self.servers[name].status = ServerStatus.ONLINE - # 保存到数据库 - await self._save_server_to_db(self.servers[name]) - return True - return False - async def get_available_server( self, required_capabilities: Optional[Dict[str, any]] = None ) -> Optional[ComfyUIServerInfo]: @@ -401,17 +384,6 @@ class ComfyUIServerManager: async with self.lock: for server in self.servers.values(): - # 检查心跳超时 - if ( - server.last_heartbeat - and current_time - server.last_heartbeat - > timedelta(seconds=self.heartbeat_timeout) - ): - server.status = ServerStatus.OFFLINE - logger.warning(f"服务器 {server.name} 心跳超时,标记为离线") - # 保存到数据库 - await self._save_server_to_db(server) - # 定期健康检查 if ( not server.last_health_check @@ -424,8 +396,7 @@ class ComfyUIServerManager: if is_healthy and server.status != ServerStatus.ONLINE: server.status = ServerStatus.ONLINE - server.last_heartbeat = current_time # 同步更新心跳时间 - logger.info(f"服务器 {server.name} 恢复在线,心跳时间已同步") + logger.info(f"服务器 {server.name} 恢复在线") elif not is_healthy and server.status == ServerStatus.ONLINE: server.status = ServerStatus.ERROR logger.warning(f"服务器 {server.name} 健康检查失败") diff --git a/workflow_service/database/models.py b/workflow_service/database/models.py index 2665bcb..285d8ea 100644 --- a/workflow_service/database/models.py +++ b/workflow_service/database/models.py @@ -120,7 +120,6 @@ class ComfyUIServer(Base): http_url = Column(String, nullable=False) ws_url = Column(String, nullable=False) status = Column(String, nullable=False, default="offline") - last_heartbeat = Column(DateTime) last_health_check = Column(DateTime) current_tasks = Column(Integer, default=0) max_concurrent_tasks = Column(Integer, default=1) @@ -135,7 +134,6 @@ class ComfyUIServer(Base): "http_url": self.http_url, "ws_url": self.ws_url, "status": self.status, - "last_heartbeat": self.last_heartbeat.isoformat() if self.last_heartbeat else None, "last_health_check": self.last_health_check.isoformat() if self.last_health_check else None, "current_tasks": self.current_tasks, "max_concurrent_tasks": self.max_concurrent_tasks, diff --git a/workflow_service/routes/comfy_server.py b/workflow_service/routes/comfy_server.py index 2dbfc37..0db7aa1 100644 --- a/workflow_service/routes/comfy_server.py +++ b/workflow_service/routes/comfy_server.py @@ -22,12 +22,6 @@ class ServerRegistrationRequest(BaseModel): ws_url: str -class ServerHeartbeatRequest(BaseModel): - """服务器心跳请求模型""" - - name: str - - class ServerUnregisterRequest(BaseModel): """服务器注销请求模型""" @@ -41,7 +35,6 @@ class ServerStatusResponse(BaseModel): http_url: str ws_url: str status: str - last_heartbeat: Optional[str] = None last_health_check: Optional[str] = None current_tasks: int max_concurrent_tasks: int @@ -74,25 +67,6 @@ async def register_server(request: ServerRegistrationRequest): raise HTTPException(status_code=500, detail=f"注册失败: {str(e)}") -@router.post("/heartbeat", response_model=Dict[str, str]) -async def update_heartbeat(request: ServerHeartbeatRequest): - """更新服务器心跳""" - try: - success = await server_manager.update_server_heartbeat(request.name) - - if success: - return { - "message": f"服务器 {request.name} 心跳更新成功", - "status": "success", - } - else: - raise HTTPException(status_code=404, detail=f"服务器 {request.name} 不存在") - - except Exception as e: - logger.error(f"更新服务器 {request.name} 心跳时发生错误: {e}") - raise HTTPException(status_code=500, detail=f"心跳更新失败: {str(e)}") - - @router.post("/unregister", response_model=Dict[str, str]) async def unregister_server(request: ServerUnregisterRequest): """注销ComfyUI服务器""" @@ -124,11 +98,6 @@ async def get_server_status(server_name: str): http_url=server_info.http_url, ws_url=server_info.ws_url, status=server_info.status.value, - last_heartbeat=( - server_info.last_heartbeat.isoformat() - if server_info.last_heartbeat - else None - ), last_health_check=( server_info.last_health_check.isoformat() if server_info.last_health_check @@ -157,9 +126,6 @@ async def list_all_servers(): http_url=server.http_url, ws_url=server.ws_url, status=server.status.value, - last_heartbeat=( - server.last_heartbeat.isoformat() if server.last_heartbeat else None - ), last_health_check=( server.last_health_check.isoformat() if server.last_health_check diff --git a/workflow_service/routes/monitor.py b/workflow_service/routes/monitor.py index 85cc0b7..eefdcf6 100644 --- a/workflow_service/routes/monitor.py +++ b/workflow_service/routes/monitor.py @@ -430,16 +430,16 @@ async def monitor_dashboard(): } }; - // 格式化心跳时间,突出显示状态 - const formatHeartbeat = (timeStr) => { + // 格式化健康检查时间 + const formatHealthCheck = (timeStr) => { if (!timeStr) return 'N/A'; try { const date = new Date(timeStr); const now = new Date(); const diff = now - date; - if (diff > 86400000) return '⚠️ 心跳超时'; // 超过1天 - if (diff > 3600000) return '⚠️ 心跳延迟'; // 超过1小时 + if (diff > 86400000) return '⚠️ 检查超时'; // 超过1天 + if (diff > 3600000) return '⚠️ 检查延迟'; // 超过1小时 if (diff < 60000) return '✅ 刚刚'; if (diff < 3600000) return `✅ ${Math.floor(diff / 60000)}分钟前`; return `✅ ${Math.floor(diff / 3600000)}小时前`; @@ -465,11 +465,7 @@ async def monitor_dashboard():
|
- 心跳: ${formatHeartbeat(server.last_heartbeat)} -
- | -
- 检查: ${formatTime(server.last_health_check)} + 检查: ${formatHealthCheck(server.last_health_check)}
${server.error ? `
${server.error}
` : ''} @@ -607,9 +603,6 @@ async def get_server_status() -> List[Dict[str, Any]]: "max_concurrent_tasks": getattr( server, "max_concurrent_tasks", 1 ), - "last_heartbeat": getattr( - server, "last_heartbeat", None - ), "last_health_check": getattr( server, "last_health_check", None ), @@ -625,9 +618,6 @@ async def get_server_status() -> List[Dict[str, Any]]: "max_concurrent_tasks": getattr( server, "max_concurrent_tasks", 1 ), - "last_heartbeat": getattr( - server, "last_heartbeat", None - ), "last_health_check": getattr( server, "last_health_check", None ), @@ -641,7 +631,6 @@ async def get_server_status() -> List[Dict[str, Any]]: "error": str(e), "current_tasks": getattr(server, "current_tasks", 0), "max_concurrent_tasks": getattr(server, "max_concurrent_tasks", 1), - "last_heartbeat": getattr(server, "last_heartbeat", None), "last_health_check": getattr(server, "last_health_check", None), }