mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
Add heartbeat event and daemon browser-liveness reaper
Introduce a `system.heartbeat` protocol event and use it as a liveness signal on the daemon side. - Track `last_seen` per connected browser, bumped on every inbound WS frame (tool response, event, ping/pong, or heartbeat). - Add a reaper task that drops any browser silent past a 60s window and purges its sessions, mirroring the WS disconnect cleanup. This releases half-open connections left behind when the OS resumes from sleep and kills the service worker without delivering a close frame, so the daemon no longer pins a phantom "connected" browser and can idle-exit normally. - Wire the reaper into both the foreground daemon and the test/embed entry point, aborting it on shutdown. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -304,6 +304,7 @@ async fn drive_connection(
|
||||
generation,
|
||||
connected_at_ms,
|
||||
version_skew,
|
||||
last_seen: std::sync::Mutex::new(std::time::Instant::now()),
|
||||
});
|
||||
state.browsers.insert(Arc::clone(&client));
|
||||
info!(
|
||||
@@ -352,15 +353,21 @@ async fn drive_connection(
|
||||
msg = reader.next() => {
|
||||
match msg {
|
||||
Some(Ok(Message::Text(t))) => {
|
||||
// Any inbound frame — tool response, event, or the
|
||||
// ~20s heartbeat — counts as proof of life.
|
||||
pump_browser.touch();
|
||||
handle_inbound_text(&pump_state, &pump_browser, &t).await;
|
||||
}
|
||||
Some(Ok(Message::Binary(_))) => {
|
||||
warn!("ignoring binary message");
|
||||
}
|
||||
Some(Ok(Message::Ping(p))) => {
|
||||
pump_browser.touch();
|
||||
let _ = writer.send(Message::Pong(p)).await;
|
||||
}
|
||||
Some(Ok(Message::Pong(_))) => {}
|
||||
Some(Ok(Message::Pong(_))) => {
|
||||
pump_browser.touch();
|
||||
}
|
||||
Some(Ok(Message::Frame(_))) => {}
|
||||
Some(Ok(Message::Close(_))) | None => break,
|
||||
Some(Err(err)) => {
|
||||
@@ -416,6 +423,11 @@ async fn handle_inbound_text(state: &Arc<DaemonState>, client: &Arc<BrowserClien
|
||||
}
|
||||
}
|
||||
Frame::Event(ev) => match ev.event {
|
||||
bsk_protocol::EventKind::SystemHeartbeat => {
|
||||
// Liveness only — `touch()` already ran for this frame in
|
||||
// the read loop, so there is nothing else to do.
|
||||
debug!(id = %client.id, "heartbeat");
|
||||
}
|
||||
bsk_protocol::EventKind::SessionWindowClosed => {
|
||||
handle_session_window_closed(state, &client.id, &ev.payload);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user