Skip to content

Commit 5ee7ac5

Browse files
committed
Implement heartbeat monitoring and auto-reconnection for stale WebSocket connections
1 parent 5e8c8a6 commit 5ee7ac5

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

apps/browser/src/background/keep-alive.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import browser from 'webextension-polyfill'
2+
import { check_and_recover_connection } from './websocket'
23

34
export const setup_keep_alive = () => {
45
if (!browser.browserAction) {
@@ -16,6 +17,7 @@ export const setup_keep_alive = () => {
1617
chrome.runtime.onInstalled.addListener(create_keep_alive_alarm)
1718
chrome.alarms.onAlarm.addListener(() => {
1819
create_keep_alive_alarm()
20+
check_and_recover_connection()
1921
})
2022
}
2123
}

apps/browser/src/background/websocket.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { DEFAULT_PORT, SECURITY_TOKENS } from '@shared/constants/websocket'
55
import browser from 'webextension-polyfill'
66
let websocket: WebSocket | null = null
77
let is_reconnecting = false
8+
let last_ping_timestamp = Date.now()
89

910
export const check_server_health = async (): Promise<boolean> => {
1011
try {
@@ -15,12 +16,34 @@ export const check_server_health = async (): Promise<boolean> => {
1516
}
1617
}
1718

19+
export const check_and_recover_connection = () => {
20+
if (websocket?.readyState === WebSocket.OPEN) {
21+
// Server sends ping every 10s. If we missed pings (e.g., system slept), connection is a zombie.
22+
if (Date.now() - last_ping_timestamp > 20000) {
23+
console.warn(
24+
'WebSocket connection is stale (no recent pings). Force reconnecting...'
25+
)
26+
websocket.close()
27+
}
28+
} else if (
29+
!is_reconnecting &&
30+
websocket?.readyState !== WebSocket.CONNECTING
31+
) {
32+
connect_websocket()
33+
}
34+
}
35+
1836
export const connect_websocket = async (): Promise<void> => {
19-
if (is_reconnecting || websocket?.readyState === WebSocket.OPEN) {
37+
if (
38+
is_reconnecting ||
39+
websocket?.readyState === WebSocket.OPEN ||
40+
websocket?.readyState === WebSocket.CONNECTING
41+
) {
2042
return
2143
}
2244

2345
is_reconnecting = true
46+
last_ping_timestamp = Date.now()
2447

2548
try {
2649
const is_healthy = await check_server_health()
@@ -44,12 +67,17 @@ export const connect_websocket = async (): Promise<void> => {
4467
websocket.onopen = () => {
4568
console.log('Connected with the VS Code!')
4669
is_reconnecting = false
70+
last_ping_timestamp = Date.now()
4771
}
4872

4973
websocket.onmessage = async (event) => {
50-
const message = JSON.parse(event.data) as WebSocketMessage
74+
const message = JSON.parse(event.data)
75+
if (message.action === 'ping') {
76+
last_ping_timestamp = Date.now()
77+
return
78+
}
5179
console.debug(message)
52-
handle_messages(message)
80+
handle_messages(message as WebSocketMessage)
5381
}
5482

5583
websocket.onclose = () => {

0 commit comments

Comments
 (0)