Fix websocket.(*Conn).timeoutLoop goroutine leak (#329)

This commit is contained in:
Nikolay Edigaryev 2025-07-11 13:23:50 +02:00 committed by GitHub
parent 49d63513b2
commit ed7921ce16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 41 additions and 0 deletions

View File

@ -17,6 +17,8 @@ import (
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
"io"
"net/http"
_ "net/http/pprof"
"os"
"strings"
)
@ -37,6 +39,7 @@ var noPKI bool
var defaultCPU uint64
var defaultMemory uint64
var username string
var addressPprof string
var debug bool
func newRunCommand() *cobra.Command {
@ -71,6 +74,8 @@ func newRunCommand() *cobra.Command {
"(\"Local Network\" permission workaround: requires starting \"orchard worker run\" as \"root\", "+
"the privileges will be then dropped to the specified user after starting the \"orchard localnetworkhelper\" "+
"helper process)")
cmd.Flags().StringVar(&addressPprof, "listen-pprof", "",
"start pprof HTTP server on localhost:6060 for diagnostic purposes (e.g. \"localhost:6060\")")
cmd.Flags().BoolVar(&debug, "debug", false, "enable debug logging")
return cmd
@ -154,6 +159,14 @@ func runWorker(cmd *cobra.Command, args []string) (err error) {
}()
workerOpts = append(workerOpts, worker.WithLogger(logger))
if addressPprof != "" {
go func() {
if err := http.ListenAndServe(addressPprof, nil); err != nil {
logger.Sugar().Errorf("pprof server failed: %v", err)
}
}()
}
workerInstance, err := worker.New(
controllerClient,
workerOpts...,

View File

@ -27,6 +27,13 @@ func (controller *Controller) rpcPortForward(ctx *gin.Context) responder.Respond
if err != nil {
return responder.Error(err)
}
defer func() {
// Ensure that we always close the accepted WebSocket connection,
// otherwise resource leak is possible[1]
//
// [1]: https://github.com/coder/websocket/issues/445#issuecomment-2053792044
_ = wsConn.CloseNow()
}()
// Respond with the established connection
proxyCtx, err := controller.connRendezvous.Respond(session, rendezvous.ResultWithErrorMessage[net.Conn]{

View File

@ -37,6 +37,13 @@ func (controller *Controller) rpcWatch(ctx *gin.Context) responder.Responder {
if err != nil {
return responder.Error(err)
}
defer func() {
// Ensure that we always close the accepted WebSocket connection,
// otherwise resource leak is possible[1]
//
// [1]: https://github.com/coder/websocket/issues/445#issuecomment-2053792044
_ = wsConn.CloseNow()
}()
// Ensure that pongs will be processed by reading
// from the connection in the background

View File

@ -102,6 +102,13 @@ func (controller *Controller) portForward(
if err != nil {
return responder.Error(err)
}
defer func() {
// Ensure that we always close the accepted WebSocket connection,
// otherwise resource leak is possible[1]
//
// [1]: https://github.com/coder/websocket/issues/445#issuecomment-2053792044
_ = wsConn.CloseNow()
}()
expectedMsgType := websocket.MessageBinary

View File

@ -55,6 +55,13 @@ func (worker *Worker) handlePortForwardV2(ctx context.Context, portForward *v1.P
return
}
defer func() {
// Ensure that we always close the accepted WebSocket connection,
// otherwise resource leak is possible[1]
//
// [1]: https://github.com/coder/websocket/issues/445#issuecomment-2053792044
_ = netConn.Close()
}()
// Proxy bytes if the connection was established without errors
if errorMessage == "" {