From a40e07ac07d52cd6db46d848bc8ac699acea6028 Mon Sep 17 00:00:00 2001 From: Andrew McGuier Date: Sat, 9 Oct 2021 15:28:59 -0400 Subject: [PATCH] Websocket CPU efficiency improvements. I see high cpu usage using the `fsdocs watch` command in current release version. It appears that the loop inside the socket is running constantly since it never yields to receive socket messages from the client, causing the process to use 100% of available CPU. Also, since the reload creates a new socket connection (and suave creates a new handler) this compounds since a new infinite loop is created after every reload. I've replaced the mutable boolean with a ManualResetEvent which all connected sockets block on until a reload is called for. Once the socket connection is closed the handler exits. I chose ManualResetEvent over AutoResetEvent because we want all connected sockets to restart at the same time, rather than individually, since someone might have multiple tabs open. --- .../BuildCommand.fs | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/FSharp.Formatting.CommandTool/BuildCommand.fs b/src/FSharp.Formatting.CommandTool/BuildCommand.fs index 1363dc6aa..8ae0518ac 100644 --- a/src/FSharp.Formatting.CommandTool/BuildCommand.fs +++ b/src/FSharp.Formatting.CommandTool/BuildCommand.fs @@ -290,21 +290,15 @@ module Serve = tag.Replace("{{PORT}}", string port) - let mutable signalHotReload = false + + let signalHotReload = new System.Threading.ManualResetEvent(false); let socketHandler (webSocket : WebSocket) _ = socket { - while true do + signalHotReload.WaitOne() |> ignore + signalHotReload.Reset() |> ignore let emptyResponse = [||] |> ByteSegment - //not sure what this was needed for - //do! - // refreshEvent.Publish - // |> Control.Async.AwaitEvent - // |> Suave.Sockets.SocketOp.ofAsync - //do! webSocket.send Text (ByteSegment (Encoding.UTF8.GetBytes "refreshed")) true - if signalHotReload then - printfn "Triggering hot reload on the client" - do! webSocket.send Close emptyResponse true - signalHotReload <- false + printfn "Triggering hot reload on the client" + do! webSocket.send Close emptyResponse true } let startWebServer outputDirectory localPort = @@ -842,7 +836,7 @@ type CoreBuildOptions(watch) = if runDocContentPhase2() then regenerateSearchIndex() ) - Serve.signalHotReload <- true + Serve.signalHotReload.Set() |> ignore } |> Async.Start ) @@ -860,7 +854,7 @@ type CoreBuildOptions(watch) = if runGeneratePhase2() then regenerateSearchIndex() ) - Serve.signalHotReload <- true + Serve.signalHotReload.Set() |> ignore } |> Async.Start )