Skip to content

Understanding and Monitoring Realtime Heartbeats

什么是心跳消息? #

🌐 What are heartbeat messages?

心跳消息是实时客户端和服务器之间发送的定期信号,用于验证 WebSocket 连接是否存活并正常运行。客户端会定期(默认:25 秒)在 phoenix 主题上发送事件类型为 heartbeat 的心跳消息,服务器则会以 phx_reply 消息进行响应。

🌐 Heartbeat messages are periodic signals sent between the Realtime client and server to verify that the WebSocket connection is alive and functioning properly. The client sends a heartbeat message on the phoenix topic with the event type heartbeat at regular intervals (default: 25 seconds), and the server responds with a phx_reply message.

这些消息作为保持连接的机制,用来检测那些可能不会立即显现的连接问题,比如无声的网络故障或中间代理的超时。

🌐 These messages serve as a keep-alive mechanism to detect connection issues that might not be immediately apparent, such as silent network failures or intermediary proxy timeouts.

心跳为什么重要 #

🌐 Why heartbeats matter

心跳消息对于维持可靠的实时连接非常重要:

🌐 Heartbeat messages are critical for maintaining reliable real-time connections:

  • 连接健康监控:它们可以检测连接何时悄悄失败,而不会触发 WebSocket 关闭事件
  • 自动恢复:当心跳超时时,客户端会自动尝试重新连接
  • 网络代理兼容性:许多网络代理和负载均衡器会关闭空闲连接;心跳可以保持连接活跃
  • 早期问题检测:心跳超时可以在用户遇到消息传递失败之前提醒你连接出现问题

没有心跳,你的应用可能看起来已连接,但实际上无法发送或接收消息。

🌐 Without heartbeats, your application might appear connected while being unable to send or receive messages.

如何处理心跳消息 #

🌐 How to handle heartbeat messages

你可以使用 onHeartbeat 方法来监控心跳生命周期事件:

🌐 You can monitor heartbeat lifecycle events using the onHeartbeat method:

1
import { createClient } from '@supabase/supabase-js'
2
import { useEffect } from 'react'
3
4
function MyComponent() {
5
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
6
7
useEffect(() => {
8
supabase.realtime.onHeartbeat((status) => {
9
console.log('Heartbeat status:', status)
10
// status can be: 'sent', 'ok', 'error', 'timeout', or 'disconnected'
11
})
12
}, [supabase])
13
14
return <div>Your app content</div>
15
}

或者在客户端初始化时配置回调:

🌐 Or configure the callback during client initialization:

1
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY, {
2
realtime: {
3
heartbeatCallback: (status) => {
4
console.log('Heartbeat status:', status)
5
},
6
},
7
})

排查心跳问题 #

🌐 Troubleshooting heartbeat issues

心跳超时频繁 #

🌐 Frequent heartbeat timeouts

如果你在心跳回调中频繁看到 timeout 状态:

🌐 If you're seeing frequent timeout status in your heartbeat callback:

  • 网络不稳定:检查你的网络连接质量
  • 防火墙/代理问题:公司防火墙或代理可能会干扰 WebSocket 连接
  • 移动应用暂停:在手机上,应用可能会被暂停,这可能会停止心跳计时器

连接超时后未重新连接

客户端会自动尝试使用指数退避重新连接(1秒、2秒、5秒、10秒)。如果你需要手动重新连接:

🌐 The client automatically attempts reconnection with exponential backoff (1s, 2s, 5s, 10s). If you need to manually reconnect:

1
import { createClient } from '@supabase/supabase-js'
2
import { useEffect, useState } from 'react'
3
4
function ConnectionStatus() {
5
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
6
const [isConnected, setIsConnected] = useState(true)
7
8
useEffect(() => {
9
supabase.realtime.onHeartbeat((status) => {
10
if (status === 'ok') {
11
setIsConnected(true)
12
} else if (status === 'timeout' || status === 'disconnected') {
13
setIsConnected(false)
14
}
15
})
16
}, [supabase])
17
18
const handleReconnect = () => {
19
supabase.realtime.connect()
20
}
21
22
return (
23
<div>
24
<p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
25
{!isConnected && <button onClick={handleReconnect}>Reconnect</button>}
26
</div>
27
)
28
}

自定义心跳间隔 #

🌐 Customizing heartbeat interval

在 React 中创建 Supabase 客户端时,你可以调整心跳频率:

🌐 You can adjust the heartbeat frequency when creating your Supabase client in React:

1
import { createClient } from '@supabase/supabase-js'
2
import { useMemo } from 'react'
3
4
function App() {
5
const supabase = useMemo(
6
() =>
7
createClient(SUPABASE_URL, SUPABASE_KEY, {
8
realtime: {
9
heartbeatIntervalMs: 15000, // Send heartbeat every 15 seconds (default: 25000)
10
},
11
}),
12
[]
13
)
14
15
return <YourApp supabase={supabase} />
16
}

注意:增加间隔可以减少网络流量,但会延迟连接失败的检测。减少间隔可以提高检测速度,但会增加开销。

🌐 Note: Increasing the interval reduces network traffic but delays detection of connection failures. Decreasing it improves detection speed but increases overhead.

Web 工作线程中的心跳错误 #

🌐 Heartbeat errors in Web workers

对于有长时间连接的 React 应用,使用 Web Workers 来防止浏览器标签页被限制:

🌐 For React applications with long-running connections, use Web Workers to prevent browser tab throttling:

1
import { createClient } from '@supabase/supabase-js'
2
import { useMemo } from 'react'
3
4
function App() {
5
const supabase = useMemo(
6
() =>
7
createClient(SUPABASE_URL, SUPABASE_KEY, {
8
realtime: {
9
worker: true,
10
workerUrl: '/worker.js', // Optional: Place in public folder
11
},
12
}),
13
[]
14
)
15
16
return <YourApp supabase={supabase} />
17
}

如果工人无法启动,请检查:

🌐 If the worker fails to start, check:

  • 浏览器支持 Web Worker
  • Worker 脚本在公共文件夹中,可以访问
  • CORS 头允许加载工作脚本

最佳实践 #

🌐 Best practices

向用户显示连接状态 #

🌐 Show connection status to users

用指示器显示连接状态:

🌐 Display connection status with an indicator:

1
import { createClient } from '@supabase/supabase-js'
2
import { useEffect, useState } from 'react'
3
4
function ConnectionIndicator() {
5
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
6
const [status, setStatus] = useState('healthy')
7
8
useEffect(() => {
9
supabase.realtime.onHeartbeat((heartbeatStatus) => {
10
if (heartbeatStatus === 'ok') {
11
setStatus('healthy')
12
} else if (heartbeatStatus === 'timeout') {
13
setStatus('poor')
14
} else if (heartbeatStatus === 'disconnected') {
15
setStatus('disconnected')
16
}
17
})
18
}, [supabase])
19
20
return (
21
<div>
22
<span>Connection: {status}</span>
23
</div>
24
)
25
}

当 React Native 应用回到前台时重新连接 #

🌐 Reconnect when React Native app comes to foreground

确保用户打开你的应用时连接是活跃的:

🌐 Ensure connection is active when user opens your app:

1
import { createClient } from '@supabase/supabase-js'
2
import { useEffect } from 'react'
3
import { AppState } from 'react-native'
4
5
function App() {
6
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
7
8
useEffect(() => {
9
const subscription = AppState.addEventListener('change', (nextAppState) => {
10
if (nextAppState === 'active') {
11
if (!supabase.realtime.isConnected()) {
12
supabase.realtime.connect()
13
}
14
}
15
})
16
17
return () => {
18
subscription.remove()
19
}
20
}, [supabase])
21
22
return <YourApp />
23
}

监控你整个应用中的连接 #

🌐 Monitor connection in your entire app

在你创建 Supabase 客户端时设置监控:

🌐 Set up monitoring when you create your Supabase client:

1
import { createClient } from '@supabase/supabase-js'
2
3
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY, {
4
realtime: {
5
heartbeatCallback: (status) => {
6
if (status === 'ok') {
7
console.log('Connection healthy')
8
} else if (status === 'timeout') {
9
console.warn('Connection slow')
10
} else if (status === 'disconnected') {
11
console.error('Disconnected')
12
}
13
},
14
},
15
})
16
17
export default supabase