fix: clear pending server requests and read client messages asynchronously

This commit is contained in:
Wojciech Nawrocki 2020-12-25 17:01:06 -05:00
parent 82497e3bcf
commit f2197e8c87
No known key found for this signature in database
GPG key ID: 4E27C2EBC32B69B7
2 changed files with 20 additions and 15 deletions

View file

@ -128,7 +128,6 @@ section ServerM
def compileDocument (m : DocumentMeta) : ServerM Unit := do
let headerSnap@⟨_, _, _, SnapshotData.headerData env msgLog opts⟩ ← Snapshots.compileHeader m.text.source
| throwServerError "Internal server error: invalid header snapshot"
let headerSnap' := { headerSnap with data := SnapshotData.headerData env msgLog opts }
let cmdSnaps ← unfoldCmdSnaps m headerSnap
(←read).docRef.set ⟨m, headerSnap, cmdSnaps⟩
@ -306,7 +305,7 @@ def workerMain : IO UInt32 := do
initAndRunWorker i o e
return 0
catch err =>
e.putStrLn (toString err)
e.putStrLn s!"Worker error: {err}"
return 1
end Lean.Server.FileWorker

View file

@ -122,10 +122,10 @@ section FileWorker
def readMessage (fw : FileWorker) : IO JsonRpc.Message := do
let msg ← fw.stdout.readLspMessage
match msg with
| Message.request id method params? =>
if let Message.response id _ := msg then
fw.pendingRequestsRef.modify (fun pendingRequests => pendingRequests.erase id)
if let Message.responseError id _ _ _ := msg then
fw.pendingRequestsRef.modify (fun pendingRequests => pendingRequests.erase id)
| _ => ()
return msg
def writeMessage (fw : FileWorker) (msg : JsonRpc.Message) : IO Unit :=
@ -179,8 +179,8 @@ section ServerM
/-- Creates a Task which forwards a worker's messages into the output stream until an event
which must be handled in the main watchdog thread (e.g. an I/O error) happens. -/
private partial def forwardMessages (fw : FileWorker) : ServerM (Task WorkerEvent) := do
let o := (←read).hOut
let rec loop : IO WorkerEvent := do
let rec loop : ServerM WorkerEvent := do
let o := (←read).hOut
try
let msg ← fw.readMessage
-- Writes to Lean I/O channels are atomic, so these won't trample on each other.
@ -192,14 +192,16 @@ section ServerM
let exitCode ← fw.proc.wait
if exitCode = 0 then
-- Worker was terminated
fw.errorPendingRequests o ErrorCode.contentModified "File header changed or file was closed"
fw.errorPendingRequests o ErrorCode.contentModified
("The file worker has been terminated. Either the header has changed,"
++ " or the file was closed, or the server is shutting down.")
return WorkerEvent.terminated
else
-- Worker crashed
fw.errorPendingRequests o ErrorCode.internalError
"Server process of file crashed, likely due to a stack overflow in user code"
return WorkerEvent.crashed err
let task ← IO.asTask loop Task.Priority.dedicated
let task ← IO.asTask (loop $ ←read) Task.Priority.dedicated
task.map $ fun
| Except.ok ev => ev
| Except.error e => WorkerEvent.crashed e
@ -373,8 +375,12 @@ section MainLoop
| ClientError (e : IO.Error)
def runClientTask : ServerM (Task ServerEvent) := do
let readMsg : IO ServerEvent := ServerEvent.ClientMsg (←(←read).hIn.readLspMessage)
let clientTask ← (←IO.asTask readMsg).map $ fun
let st ← read
let readMsgAction : IO ServerEvent := do
/- Runs asynchronously. -/
let msg ← st.hIn.readLspMessage
ServerEvent.ClientMsg msg
let clientTask := (←IO.asTask readMsgAction).map $ fun
| Except.ok ev => ev
| Except.error e => ServerEvent.ClientError e
return clientTask
@ -430,9 +436,9 @@ def initAndRunWatchdogAux : ServerM Unit := do
mainLoop clientTask
let Message.notification "exit" none ← st.hIn.readLspMessage
| throwServerError "Expected an exit notification"
catch err =>
shutdown
throw err
catch err =>
shutdown
throw err
def initAndRunWatchdog (i o e : FS.Stream) : IO Unit := do
let workerPath ← match (←IO.getEnv "LEAN_WORKER_PATH") with
@ -473,7 +479,7 @@ def watchdogMain : IO UInt32 := do
initAndRunWatchdog i o e
return 0
catch err =>
e.putStrLn (toString err)
e.putStrLn s!"Watchdog error: {err}"
return 1
end Lean.Server.Watchdog