robtaussig / react-use-websocket

React Hook for WebSocket communication
MIT License
1.62k stars 135 forks source link

heartbeat seems not working as expected #233

Open harikt opened 8 months ago

harikt commented 8 months ago

Hey,

I have been experimenting with the heartbeat feature and as reported on comment https://github.com/robtaussig/react-use-websocket/pull/206#issuecomment-1867894798 , this seems not sending any messages via websocket.

const {
    sendMessage,
    sendJsonMessage,
    lastJsonMessage,
    readyState,
    getWebSocket,
} = useWebSocket(socketUrl, {
    onClose: (event) => {  console.log("onClose : " + event) },
    onError: (event) => {  console.log("onError : " + event) },
    onOpen: () => {
        console.log("Connection opened.");      
    },
    // share: true,
    skipAssert: true,
    retryOnError: true,
    //Will attempt to reconnect on all close events, such as server shutting down
    shouldReconnect: (closeEvent) => {
        return true;
    },
    // Defaults to 20, so increased to 10000
    reconnectAttempts: 10000,
    //attemptNumber will be 0 the first time it attempts to reconnect, so this equation results in a reconnect pattern of 1 second, 2 seconds, 4 seconds, 8 seconds, and then caps at 10 seconds until the maximum number of attempts is reached
    reconnectInterval: (attemptNumber) => {
        const maxTime = 300; // Maximum time for reconnection
        const baseTime = 2; // Base time for exponential backoff

        // Calculate reconnect time using exponential backoff
        const reconnectTime = Math.min(maxTime, Math.pow(baseTime, attemptNumber)) * 1000;

        console.log("Reconnect attempt will be made in : " + reconnectTime + " ms");

        return reconnectTime;
    },
    // Default
    heartbeat: true,
}, connect);

Option 2 for heartbeat

heartbeat: {
    message: 'ping',
    returnMessage: 'pong',
    timeout: 60000, // 1 minute, if no response is received, the connection will be closed
    interval: 2500, // every 25 seconds, a ping message will be sent
},

Option 3 for heartbeat

heartbeat: {
    message: function () {
        return JSON.stringify({
            type: 'ping'
        });
    },

    returnMessage: function () {
        return JSON.stringify({
            status: 'success',
            message: 'pong',
        });
    },
    timeout: 60000, // 1 minute, if no response is received, the connection will be closed
    interval: 2500, // every 25 seconds, a ping message will be sent
}

Note : You can see one of the option I choose is skipAssert: true, . This was because of error I was getting

app.js:22773 Uncaught (in promise) Error
    at assertIsWebSocket (app.js:22773:17)
    at bindCloseHandler (app.js:22836:38)
    at attachListeners (app.js:22897:34)
    at createOrJoinSocket (app.js:23097:56)
    at app.js:23507:85
    at step (app.js:23387:25)
    at Object.next (app.js:23334:20)
    at fulfilled (app.js:23305:30)

image

So using skipAssert: true, has fixed the error. The note probably is another issue I should open.

harikt commented 8 months ago

As an alternative approach this is what I did. If this helps anyone.

// Ping every 60 second
const HEARTBEAT_INTERVAL = 60000;

useEffect(() => {
    // Start heartbeat interval
    const heartbeatInterval = setInterval(() => {
        sendJsonMessage({
            type: 'ping'
        });
    }, HEARTBEAT_INTERVAL);

    // Clean up interval on component unmount
    return () => clearInterval(heartbeatInterval);
}, [sendJsonMessage]);