Skip to content

Commit f015902

Browse files
committed
runServerWith gracefully exit by returning exit code 1
1 parent 6097552 commit f015902

File tree

3 files changed

+36
-31
lines changed

3 files changed

+36
-31
lines changed

lsp/src/Language/LSP/Server/Control.hs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,9 @@ runServerWith ioLogger logger clientIn clientOut serverDefinition = do
149149
cout <- atomically newTChan :: IO (TChan FromServerMessage)
150150
withAsync (sendServer ioLogger cout clientOut) $ \_sendAsync -> do
151151
let sendMsg = atomically . writeTChan cout
152-
ioLoop ioLogger logger clientIn serverDefinition emptyVFS sendMsg
152+
res <- ioLoop ioLogger logger clientIn serverDefinition emptyVFS sendMsg
153153
ioLogger <& ServerStopped `WithSeverity` Info
154-
return 0
154+
return res
155155

156156
-- ---------------------------------------------------------------------
157157

@@ -163,33 +163,37 @@ ioLoop ::
163163
ServerDefinition config ->
164164
VFS ->
165165
(FromServerMessage -> IO ()) ->
166-
IO ()
166+
IO Int
167167
ioLoop ioLogger logger clientIn serverDefinition vfs sendMsg = do
168168
minitialize <- parseOne ioLogger clientIn (parse parser "")
169169
case minitialize of
170-
Nothing -> pure ()
170+
Nothing -> pure 1
171171
Just (msg, remainder) -> do
172172
case J.eitherDecode $ BSL.fromStrict msg of
173-
Left err -> ioLogger <& DecodeInitializeError err `WithSeverity` Error
173+
Left err -> do
174+
ioLogger <& DecodeInitializeError err `WithSeverity` Error
175+
return 1
174176
Right initialize -> do
175177
mInitResp <- Processing.initializeRequestHandler pioLogger serverDefinition vfs sendMsg initialize
176178
case mInitResp of
177-
Nothing -> pure ()
179+
Nothing -> pure 1
178180
Just env -> runLspT env $ loop (parse parser remainder)
179181
where
180182
pioLogger = L.cmap (fmap LspProcessingLog) ioLogger
181183
pLogger = L.cmap (fmap LspProcessingLog) logger
182184

183-
loop :: Result BS.ByteString -> LspM config ()
185+
loop :: Result BS.ByteString -> LspM config Int
184186
loop = go
185187
where
186188
go r = do
187-
res <- parseOne logger clientIn r
188-
case res of
189-
Nothing -> pure ()
190-
Just (msg, remainder) -> do
191-
Processing.processMessage pLogger $ BSL.fromStrict msg
192-
go (parse parser remainder)
189+
b <- isExiting
190+
if b then pure 0 else do
191+
res <- parseOne logger clientIn r
192+
case res of
193+
Nothing -> pure 1
194+
Just (msg, remainder) -> do
195+
Processing.processMessage pLogger $ BSL.fromStrict msg
196+
go (parse parser remainder)
193197

194198
parser = do
195199
try contentType <|> return ()

lsp/src/Language/LSP/Server/Core.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ data LanguageContextState config = LanguageContextState
211211
, resRegistrationsReq :: !(TVar (RegistrationMap Request))
212212
, resLspId :: !(TVar Int32)
213213
, resShutdown :: !(C.Barrier ())
214+
, resExit :: !(C.Barrier ())
214215
-- ^ Has the server received 'shutdown'? Can be used to conveniently trigger e.g. thread termination,
215216
-- but if you need a cleanup action to terminate before exiting, then you should install a full
216217
-- 'shutdown' handler
@@ -754,6 +755,14 @@ isShuttingDown = do
754755
Just _ -> True
755756
Nothing -> False
756757

758+
isExiting :: (m ~ LspM config) => m Bool
759+
isExiting = do
760+
b <- resExit . resState <$> getLspEnv
761+
r <- liftIO $ C.waitBarrierMaybe b
762+
pure $ case r of
763+
Just _ -> True
764+
Nothing -> False
765+
757766
-- | Blocks until the server receives a 'shutdown' request.
758767
waitShuttingDown :: (m ~ LspM config) => m ()
759768
waitShuttingDown = do

lsp/src/Language/LSP/Server/Processing.hs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ initializeRequestHandler logger ServerDefinition{..} vfs sendFunc req = do
172172
resRegistrationsReq <- newTVarIO mempty
173173
resLspId <- newTVarIO 0
174174
resShutdown <- C.newBarrier
175+
resExit <- C.newBarrier
175176
pure LanguageContextState{..}
176177

177178
-- Call the 'duringInitialization' callback to let the server kick stuff up
@@ -440,6 +441,7 @@ handle logger m msg =
440441
SMethod_WorkspaceDidChangeConfiguration -> handle' logger (Just $ handleDidChangeConfiguration logger) m msg
441442
-- See Note [LSP configuration]
442443
SMethod_Initialized -> handle' logger (Just $ \_ -> initialDynamicRegistrations logger >> requestConfigUpdate (cmap (fmap LspCore) logger)) m msg
444+
SMethod_Exit -> exitNotificationHandler logger msg
443445
SMethod_Shutdown -> handle' logger (Just $ \_ -> signalShutdown) m msg
444446
where
445447
-- See Note [Shutdown]
@@ -466,18 +468,9 @@ handle' ::
466468
m ()
467469
handle' logger mAction m msg = do
468470
shutdown <- isShuttingDown
469-
-- These are the methods that we are allowed to process during shutdown.
470-
-- The reason that we do not include 'shutdown' itself here is because
471-
-- by the time we get the first 'shutdown' message, isShuttingDown will
472-
-- still be false, so we would still be able to process it.
473-
-- This ensures we won't process the second 'shutdown' message and only
474-
-- process 'exit' during shutdown.
475-
let allowedMethod m = case (splitClientMethod m, m) of
476-
(IsClientNot, SMethod_Exit) -> True
477-
_ -> False
478471

479472
case mAction of
480-
Just f | not shutdown || allowedMethod m -> f msg
473+
Just f | not shutdown -> f msg
481474
_ -> pure ()
482475

483476
dynReqHandlers <- getsState resRegistrationsReq
@@ -488,14 +481,12 @@ handle' logger mAction m msg = do
488481

489482
case splitClientMethod m of
490483
-- See Note [Shutdown]
491-
IsClientNot | shutdown, not (allowedMethod m) -> notificationDuringShutdown
484+
IsClientNot | shutdown -> notificationDuringShutdown
492485
IsClientNot -> case pickHandler dynNotHandlers notHandlers of
493486
Just h -> liftIO $ h msg
494-
Nothing
495-
| SMethod_Exit <- m -> exitNotificationHandler logger msg
496-
| otherwise -> missingNotificationHandler
487+
Nothing | otherwise -> missingNotificationHandler
497488
-- See Note [Shutdown]
498-
IsClientReq | shutdown, not (allowedMethod m) -> requestDuringShutdown msg
489+
IsClientReq | shutdown -> requestDuringShutdown msg
499490
IsClientReq -> case pickHandler dynReqHandlers reqHandlers of
500491
Just h -> liftIO $ h msg (runLspT env . sendResponse msg)
501492
Nothing
@@ -556,10 +547,11 @@ progressCancelHandler logger (TNotificationMessage _ _ (WorkDoneProgressCancelPa
556547
logger <& ProgressCancel tid `WithSeverity` Debug
557548
liftIO cancelAction
558549

559-
exitNotificationHandler :: (MonadIO m) => LogAction m (WithSeverity LspProcessingLog) -> Handler m Method_Exit
550+
exitNotificationHandler :: (MonadIO m, MonadLsp config0 m) => LogAction m (WithSeverity LspProcessingLog) -> Handler m Method_Exit
560551
exitNotificationHandler logger _ = do
561-
logger <& Exiting `WithSeverity` Info
562-
liftIO exitSuccess
552+
logger <& ShuttingDown `WithSeverity` Info
553+
b <- resExit . resState <$> getLspEnv
554+
liftIO $ signalBarrier b ()
563555

564556
-- | Default Shutdown handler
565557
shutdownRequestHandler :: Handler IO Method_Shutdown

0 commit comments

Comments
 (0)