Skip to content

[WebRTC Demo] 推理服务注册缺少心跳保活,导致前端报 'Server at capacity' #74

@seasidedog24

Description

@seasidedog24

问题描述

按照 WebRTC Demo 文档 在 macOS (M4, 24GB) 上完成本地部署后,前端页面显示:

Server at capacity. Please try again later.

点击 Start Call 无法发起通话。

根因分析

排查后端日志发现:

voice_chat - ERROR - routes.py:79:login - 登录失败: 503: 没有可用的推理服务

原因是 cpp_server/minicpmo_cpp_http_server.py 中的 register_service_node() 函数 只在服务启动时注册一次(第 821-823 行),没有周期性心跳保活机制:

# lifespan 函数中,只注册一次
try:
    register_service_node(port=app.state.port, duplex_mode=app.state.default_duplex_mode)
except Exception as e:
    print(f"服务节点注册失败: {e}", flush=True)

而后端的 heartbeat_monitor 每隔几秒会检查并清理过期的服务注册。由于推理服务没有定期发送心跳,注册很快就被标记为过期并清除,导致后端找不到可用的推理节点。

此外,如果 deploy_all.sh 执行过程中推理服务因依赖缺失(如 ModuleNotFoundError: No module named 'librosa')等原因启动失败,手动修复后重启推理服务,也会因为心跳缺失而无法被后端识别。

复现步骤

  1. 按文档执行 deploy_all.sh --duplex
  2. 等待所有 Docker 容器启动(前端/后端/LiveKit/Redis)
  3. 推理服务启动并成功注册
  4. 等待约 30-60 秒
  5. 打开 http://localhost:3000,点击 Start Call
  6. 看到 "Server at capacity. Please try again later."

临时解决方案

在宿主机上运行一个定时重新注册的脚本:

LOCAL_IP=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | head -1 | awk '{print $2}')
while true; do
  curl -s -X POST "http://localhost:8021/api/inference/register" \
    -H "Content-Type: application/json" \
    -d "{\"ip\": \"$LOCAL_IP\", \"port\": 9060, \"model_port\": 9060, \"model_type\": \"duplex\", \"session_type\": \"release\", \"service_name\": \"o45-cpp\"}"
  sleep 30
done

建议修复方案

minicpmo_cpp_http_server.py 中增加后台心跳线程,定期向后端重新注册:

import threading

def _heartbeat_loop(port: int, duplex_mode: bool, interval: int = 30):
    """后台心跳线程,定期向后端重新注册服务"""
    while True:
        try:
            register_service_node(port=port, duplex_mode=duplex_mode)
        except Exception as e:
            print(f"心跳注册异常: {e}", flush=True)
        time.sleep(interval)

# 在 lifespan 中启动时调用:
heartbeat_thread = threading.Thread(
    target=_heartbeat_loop,
    args=(app.state.port, app.state.default_duplex_mode),
    daemon=True
)
heartbeat_thread.start()

环境信息

  • 设备: Mac mini M4, 24GB
  • macOS: Darwin 25.2.0
  • Docker Desktop: 4.59.1
  • Python: 3.14.2
  • 模型: MiniCPM-o-4_5 Q4_K_M
  • 部署模式: duplex

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions