fix(channel): update last_recv on WS Ping/Pong frames in Lark channel

Feishu WebSocket server sends native WS Ping frames as keep-alive probes.
ZeroClaw correctly replied with Pong but did not update last_recv, so the
heartbeat watchdog (WS_HEARTBEAT_TIMEOUT = 300s) triggered a forced
reconnect every 5 minutes even when the connection was healthy.

Two fixes:
- WsMsg::Ping: update last_recv before sending Pong
- WsMsg::Pong: handle explicitly and update last_recv (was silently
  swallowed by the wildcard arm)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wonder_land 2026-02-19 15:40:04 +08:00 committed by Chummy
parent 1bf5582c83
commit 3108ffe3e7

View file

@ -322,7 +322,8 @@ impl LarkChannel {
msg = read.next() => { msg = read.next() => {
let raw = match msg { let raw = match msg {
Some(Ok(WsMsg::Binary(b))) => { last_recv = Instant::now(); b } Some(Ok(WsMsg::Binary(b))) => { last_recv = Instant::now(); b }
Some(Ok(WsMsg::Ping(d))) => { let _ = write.send(WsMsg::Pong(d)).await; continue; } Some(Ok(WsMsg::Ping(d))) => { last_recv = Instant::now(); let _ = write.send(WsMsg::Pong(d)).await; continue; }
Some(Ok(WsMsg::Pong(_))) => { last_recv = Instant::now(); continue; }
Some(Ok(WsMsg::Close(_))) | None => { tracing::info!("Lark: WS closed — reconnecting"); break; } Some(Ok(WsMsg::Close(_))) | None => { tracing::info!("Lark: WS closed — reconnecting"); break; }
Some(Err(e)) => { tracing::error!("Lark: WS read error: {e}"); break; } Some(Err(e)) => { tracing::error!("Lark: WS read error: {e}"); break; }
_ => continue, _ => continue,