Daniyal
Daniyal

Reputation: 341

Websocket freezes if disconnected abnormally

I've created a simple websocket that publishes a JSON stream. I't works fine most of the time except for few cases where I think while looping through the clients to send them message, it gets hung up on a client that is being disconnected abnormally. What measure can I add to this code to mitigate it?

Client.go

import (
    "github.com/gorilla/websocket"
)

type client struct {
    socket *websocket.Conn

    send chan *Message
}

func (c *client) read() {
    defer c.socket.Close()
    for {
        _, _, err := c.socket.ReadMessage()
        if err != nil {
            log.Info("Websocket: %s", err)
            break
        }
    }
}

func (c *client) write() {
    defer c.socket.Close()
    for msg := range c.send {
        err := c.socket.WriteJSON(msg)
        if err != nil {
            break
        }
    }
}

Stream.go

import (
    "net/http"

    "github.com/gorilla/websocket"
)

const (
    socketBufferSize  = 1024
    messageBufferSize = 256
)

var upgrader = &websocket.Upgrader{
    ReadBufferSize:  socketBufferSize,
    WriteBufferSize: socketBufferSize,
}

type Stream struct {
    Send chan *Message

    join chan *client

    leave chan *client

    clients map[*client]bool
}

func (s *Stream) Run() {
    for {
        select {
        case client := <-s.join: // joining
            s.clients[client] = true
        case client := <-s.leave: // leaving
            delete(s.clients, client)
            close(client.send)
        case msg := <-s.Send: // send message to all clients
            for client := range s.clients {
                client.send <- msg
            }
        }
    }
}

func (s *Stream) ServeHTTP(w http.ResponseWriter, res *http.Request) {
    socket, err := upgrader.Upgrade(w, res, nil)
    if err != nil {
        log.Error(err)
        return
    }

    defer func() {
        socket.Close()
    }()

    client := &client{
        socket: socket,
        send:   make(chan *Message, messageBufferSize),
    }

    s.join <- client
    defer func() { s.leave <- client }()

    go client.write()
    client.read()
}        

Upvotes: 1

Views: 1056

Answers (1)

Thundercat
Thundercat

Reputation: 120941

See the Gorilla Chat Application for an example of how to avoid blocking on a client.

The key parts are:

Upvotes: 4

Related Questions