I have an app which uses the Gorilla Websockets at: “GitHub - gorilla/websocket: Package gorilla/websocket is a fast, well-tested and widely used WebSocket implementation for Go.”
My app opens the connection, sends a list of stock symbols then, in a loop, reads the messages returned through that connection until it is cancelled or errors out.
Using Go routines, I want to monitor multiple lists of stocks concurrently. The error occurs when the 2nd connection is opened and the first connection is reading messages. In my code I identify the routines by iterationNumber and due to the way go routines work there is no guarantee which connection will be attempted first. I am getting an error when I run this, so I extracted the necessary code to exemplify the issue. I am pretty new to web sockets, so I’m probably just doing something incorrectly. I will send the example code and results:
package main
import (
"fmt"
"github.com/gorilla/websocket"
"net/url"
"sync"
)
type Stock struct {
Symbol string `json:"symbol"`
Type string `json:"type"`
}
func main() {
// URL and token for the WebSocket connection
var wg *sync.WaitGroup = &sync.WaitGroup{}
for i := 0; i < 2; i++ {
wg.Add(1)
go processStocks(i, wg)
}
wg.Wait()
}
func processStocks(interationNumber int, wg *sync.WaitGroup) {
iterationStr := fmt.Sprintf("%d", interationNumber)
u := url.URL{Scheme: "wss", Host: "ws.finnhub.io", RawQuery: "token=cbbb00iad3ibhoa1vbcg"}
fmt.Printf("begin processStocks() for iteration: %s\n", iterationStr)
// List of stock symbols
stocks := []Stock{
{"IBM", "subscribe"},
// Add more stocks here
}
defer wg.Done()
// Create a new WebSocket connection
fmt.Printf("begin Dial() for iteration: %s\n", iterationStr)
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
//cAddress := fmt.Sprintf("%p", c)
fmt.Printf("failed dial error for iteration:%s address:%p: %v\n", iterationStr, c, err)
} else {
fmt.Printf("successful connection at address: %p for iteration: %s \n", c, iterationStr)
}
defer func(c *websocket.Conn) {
err := c.Close()
if err != nil {
fmt.Printf("iteration %s Close error: %v\n", iterationStr, err)
}
}(c)
// Send the list of stock symbols
for _, stock := range stocks {
fmt.Printf("begin WriteJSON() for iteration: %s address: %p\n", iterationStr, c)
err := c.WriteJSON(stock)
if err != nil {
fmt.Printf("iteration %s write error: %v\n", iterationStr, err)
return
} else {
fmt.Printf("successful write at address: %p for iteration: %s \n", c, iterationStr)
}
}
// Endless loop to read the results
for {
fmt.Printf("begin ReadMessage() for iteration:%s address:%p\n", iterationStr, c)
_, message, err := c.ReadMessage()
if err != nil {
fmt.Printf("iteration %s read error: %v address:%p: \n", iterationStr, err, c)
return
} else {
fmt.Printf("iteration %s successful read: [%s] address:%p: \n", iterationStr, message, c)
}
}
}
the output:
begin processStocks() for iteration: 1
begin Dial() for iteration: 1
begin processStocks() for iteration: 0
begin Dial() for iteration: 0
successful connection at address: 0x14000012580 for iteration: 0
begin WriteJSON() for iteration: 0 address: 0x14000012580
successful write at address: 0x14000012580 for iteration: 0
begin ReadMessage() for iteration:0 address:0x14000012580
*iteration 0 read error: websocket: close 1006 (abnormal closure): unexpected EOF address:0x14000012580:*
successful connection at address: 0x140000126e0 for iteration: 1
begin WriteJSON() for iteration: 1 address: 0x140000126e0
successful write at address: 0x140000126e0 for iteration: 1
begin ReadMessage() for iteration:1 address:0x140000126e0
iteration 1 successful read: [{"data":[{"c":["1","12"],"p":144.995,"s":"IBM","t":1691083530560,"v":1}],"type":"trade"}] address:0x140000126e0:
begin ReadMessage() for iteration:1 address:0x140000126e0
BTW, this has my key in it so you can recreate the issue, but I will be changing it soon and it’s free anyway.