Skip to content

Commit 34ffaec

Browse files
author
wakqasahmed
committed
Return from websocket handler after write/read error instead of busy-looping
1 parent 87899ff commit 34ffaec

4 files changed

Lines changed: 87 additions & 0 deletions

File tree

cookbook/websocket/gorilla/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ func hello(c *echo.Context) error {
2525
err := ws.WriteMessage(websocket.TextMessage, []byte("Hello, Client!"))
2626
if err != nil {
2727
c.Logger().Error("failed to write WS message", "error", err)
28+
return nil
2829
}
2930

3031
// Read
3132
_, msg, err := ws.ReadMessage()
3233
if err != nil {
3334
c.Logger().Error("failed to read WS message", "error", err)
35+
return nil
3436
}
3537
fmt.Printf("%s\n", msg)
3638
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
import (
4+
"log/slog"
5+
"net/http/httptest"
6+
"strings"
7+
"testing"
8+
"time"
9+
10+
"github.com/gorilla/websocket"
11+
"github.com/labstack/echo/v5"
12+
)
13+
14+
func TestHelloReturnsAfterClientDisconnect(t *testing.T) {
15+
e := echo.New()
16+
e.Logger = slog.New(slog.DiscardHandler)
17+
handlerReturned := make(chan struct{})
18+
e.GET("/ws", func(c *echo.Context) error {
19+
err := hello(c)
20+
close(handlerReturned)
21+
return err
22+
})
23+
24+
server := httptest.NewServer(e)
25+
defer server.Close()
26+
27+
wsURL := "ws" + strings.TrimPrefix(server.URL, "http") + "/ws"
28+
ws, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
29+
if err != nil {
30+
t.Fatalf("failed to connect websocket client: %v", err)
31+
}
32+
if err := ws.Close(); err != nil {
33+
t.Fatalf("failed to close websocket client: %v", err)
34+
}
35+
36+
select {
37+
case <-handlerReturned:
38+
case <-time.After(2 * time.Second):
39+
t.Fatal("websocket handler did not return after client disconnected")
40+
}
41+
}

cookbook/websocket/net/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ func hello(c *echo.Context) error {
1616
// Write
1717
if err := websocket.Message.Send(ws, "Hello, Client!"); err != nil {
1818
c.Logger().Error("failed to write WS message", "error", err)
19+
return
1920
}
2021

2122
// Read
2223
msg := ""
2324
if err := websocket.Message.Receive(ws, &msg); err != nil {
2425
c.Logger().Error("failed to write WS message", "error", err)
26+
return
2527
}
2628
fmt.Printf("%s\n", msg)
2729
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"log/slog"
5+
"net/http/httptest"
6+
"strings"
7+
"testing"
8+
"time"
9+
10+
"github.com/labstack/echo/v5"
11+
"golang.org/x/net/websocket"
12+
)
13+
14+
func TestHelloReturnsAfterClientDisconnect(t *testing.T) {
15+
e := echo.New()
16+
e.Logger = slog.New(slog.DiscardHandler)
17+
handlerReturned := make(chan struct{})
18+
e.GET("/ws", func(c *echo.Context) error {
19+
err := hello(c)
20+
close(handlerReturned)
21+
return err
22+
})
23+
24+
server := httptest.NewServer(e)
25+
wsURL := "ws" + strings.TrimPrefix(server.URL, "http") + "/ws"
26+
ws, err := websocket.Dial(wsURL, "", server.URL)
27+
if err != nil {
28+
server.Close()
29+
t.Fatalf("failed to connect websocket client: %v", err)
30+
}
31+
if err := ws.Close(); err != nil {
32+
server.CloseClientConnections()
33+
t.Fatalf("failed to close websocket client: %v", err)
34+
}
35+
36+
select {
37+
case <-handlerReturned:
38+
server.Close()
39+
case <-time.After(2 * time.Second):
40+
t.Fatal("websocket handler did not return after client disconnected")
41+
}
42+
}

0 commit comments

Comments
 (0)