Heartbeat Event

Heartbeat Event 是 Agent Runtime 定期发送的空事件,用于保持 SSE 连接存活,防止中间代理(Nginx、CDN)因超时而断开连接。

#type / concept #status / evergreen #tech / ai #tech / network

[!info] related notes

Heartbeat Event

一句话定义

Heartbeat Event 是 Agent Runtime 定期发送的空事件,用于保持 SSE 连接存活。Nginx 默认 60 秒没有数据就会断开连接,LLM 推理可能需要 30 秒以上,心跳防止连接被误断。

它解决什么问题

LLM 推理期间(特别是复杂推理),可能 30-60 秒没有输出。中间的代理(Nginx、CDN、负载均衡器)会认为连接空闲而断开。心跳让代理知道”连接还活着”。

核心原理

心跳机制

LLM 推理中 (30秒无输出)

    ├─ 0s: 上一个事件
    ├─ 15s: heartbeat
    ├─ 30s: heartbeat
    └─ 45s: LLM 开始输出

Python 实现

class HeartbeatManager:
    def __init__(self, interval: int = 15):
        self.interval = interval
        self._task = None

    async def start(self, emit_fn):
        async def heartbeat_loop():
            while True:
                await asyncio.sleep(self.interval)
                await emit_fn(RunEvent(event="heartbeat", data={}))

        self._task = asyncio.create_task(heartbeat_loop())

    def stop(self):
        if self._task:
            self._task.cancel()

Go 实现

func heartbeatTicker(w http.ResponseWriter, flusher http.Flusher, done <-chan struct{}) {
    ticker := time.NewTicker(15 * time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-ticker.C:
            fmt.Fprintf(w, "event: heartbeat\ndata: {}\n\n")
            flusher.Flush()
        case <-done:
            return
        }
    }
}

前端处理

// 前端应该忽略 heartbeat 事件,不触发状态更新
es.addEventListener('heartbeat', () => {
  // 只用于保活,不做任何处理
});

常见坑

  1. 不做心跳: Nginx 60 秒超时断开连接
  2. 心跳太频繁: 增加不必要的网络流量
  3. 心跳触发前端更新: heartbeat 应该被忽略
  4. 不随事件重置: 有正常事件时不需要心跳

参考资料

创建于 2026/6/30 更新于 2026/7/15