JavaScript

# Websocket implementation with custom reconnect timer class

If you have to handle reconnection of a websocket in case network disconnection or retry connecting if your app is initialised and websocket connection gets a error. We can handle such cases to provide a seamless websocket experience to the user by implementing a Timer class which automatically tried to reconnect the websocket on specified time intervals untill our websocket connection is alive.

What we aim to achieve is that we should be able to

  1. Decide the time interval of reconnection based on number of tries. i.e. we will increasae the time to try reconnecting the socket with every try, lets say we will try to connect after 1 sec on first failed connection then after 2 sec, 5 sec and then after every 10 second.

  2. Take a callback function in which we can define how to handle closing previous connection and try creating a new one after the specified time interval which is based on number of tries.

# Creating Custom websocket Class

Firstly lets create a simple class to handle websocket connection and disconnection of the websocket:

  1. The class object takes url as parameter which is the url to make connection at.

  2. connect() method to handle creating a new websocket connection and its onopen, onclsoe & onerror methods.

  3. disconnect() method to handle closing websocket connection.

export default class CustomSocket {

    // Constructor which takes socket URL as parameter
    constructor(url) {
        this.customSocket = null
        this.socketUrl = url
    }

    // Create socket and define socket methods
    connect(){

        this.customSocket = new WebSocket(this.socketUrl)

        // onopen - called when connection is open and ready to send and receive data.
        this.customSocket.onopen = (event) => {
            
        }

        // onclsoe - called when the connection's closes.
        this.customSocket.onclose = (event) => {
            
        }

        // onerror - called when an error occurs.
        this.customSocket.onerror = (event) => {

        }

        // onmessage - called when a message is received from the server.
        this.customSocket.onmessage = (event) => {
        
        }
    }

    // close socket connection 
    disconnect() {
        this.customSocket.close()
    }
}
  1. Let's add custom reconnectAfterMs method to our CustomSocket class which will contain a array of time intervals to retry connecting websocket based on the number of reconnection attempt i.e. tries. If first reconnect attempt then tries will be 1 and time interval to try after would be 1000 Ms (1 sec) and at second attemt 2000 Ms (2 sec), then 5000 Ms (5 sec) and after that every 10000 Ms (10 sec).
export default class CustomSocket {

    // Constructor which takes socket URL as parameter
    constructor(url) {
        this.customSocket = null
        this.socketUrl = url
    }

    // Reconnect time intervals based on tries
    reconnectAfterMs(tries){
        return [1000, 2000, 5000, 10000][tries - 1] || 10000
    }

    // Create socket and define socket methods
    connect(){

        this.customSocket = new WebSocket(this.socketUrl)

        // onopen - called when connection is open and ready to send and receive data.
        this.customSocket.onopen = (event) => {
            
        }

        // onclsoe - called when the connection's closes.
        this.customSocket.onclose = (event) => {
            
        }

        // onerror - called when an error occurs.
        this.customSocket.onerror = (event) => {

        }

        // onmessage - called when a message is received from the server.
        this.customSocket.onmessage = (event) => {
        
        }
    }

    // close socket connection 
    disconnect() {
        this.customSocket.close()
    }
}

# Creating the Timer class

Let's create the timer class which takes a callback method ( to call at each attempt) and a timerCalc method (to define the time interval to retry connecting at after each try).

class Timer {
    constructor(callback, timerCalc){
      this.callback  = callback;
      this.timerCalc = timerCalc;
      this.timer     = null;
      this.tries     = 0;
    }
  
    reset(){
      this.tries = 0
      clearTimeout(this.timer)
    }

    scheduleTimeout(){
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.tries = this.tries + 1
        this.callback()
      }, this.timerCalc(this.tries + 1))
    }
  }

We have already defined our reconnectAfterMs method previously which we will pass as the timerCalc method to the object of this class.

  1. scheduleTimeout() - Here we are clearing the previous timeouts and creating a new timer as setTimeout with time based on number of tries using the timerCalc method.

  2. reset() - A simple method to reset the Timer.

# Using Timer Class in our CustomSocket Class

We will create a reconnectTimer object from the Timer class and give a simple callback function to the object which will call the disconnect() and then connect() method of CustomSocket Class and our reconnectAfterMs as the timerCalc method.

We will call the scheduleTimeout method onclose and reset our onclose method in disconnect method otherwise it will keep on tring to connect when we purposely want to close the sokcet also. The final code will look like this:

export default class CustomSocket {

    // Constructor which takes socket URL as parameter
    constructor(url) {
        this.customSocket = null
        this.socketUrl = url
        this.reconnectTimer = new Timer(() => {
            this.disconnect()
            this.connect()
        }, this.reconnectAfterMs)
    }

    // Reconnect time intervals based on tries
    reconnectAfterMs(tries){
        return [1000, 2000, 5000, 10000][tries - 1] || 10000
    }

    // Create socket and define socket methods
    connect(){

        // Create new socket
        this.customSocket = new WebSocket(this.socketUrl)

        // onopen - called when connection is open and ready to send and receive data.
        this.customSocket.onopen = (event) => {
            
        }

        // onclsoe - called when the connection's closes.
        this.customSocket.onclose = (event) => {

            // On connection close try again to connect
            this.reconnectTimer.scheduleTimeout()

        }

        // onerror - called when an error occurs.
        this.customSocket.onerror = (event) => {

        }

        // onmessage - called when a message is received from the server.
        this.customSocket.onmessage = (event) => {
        
        }
    }

    // close socket connection 
    disconnect() {

        // resetting in close method to stop timer on disconnect
        this.customSocket.onclose = function(){}
        // Closing socket
        this.customSocket.close()
    }
}

I will add a githib project with an example below.

GitHub Link : Websocket implementation with custom reconnect timer class



By Ashish Kanwar Singh

Building products that matter
Senior Software Engineer @XanaduAI

Ashish Kanwar Singh's DEV Profile