Skip to content

Commit 202706e

Browse files
committed
[#222] Prevent progress bar rendering from abort
Problem: It seems that the current progress bar rendering action is not completely protected against exceptions. Solution: As it is an action that runs for a short amount of time and we really want it to not be interrputed, we can wrap it with uninterruptibleMask. The resulting rendering loop also gets simpler with this change.
1 parent 297324c commit 202706e

File tree

1 file changed

+9
-33
lines changed

1 file changed

+9
-33
lines changed

src/Xrefcheck/Verify.hs

+9-33
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ module Xrefcheck.Verify
2727

2828
import Universum
2929

30-
import Control.Concurrent.Async (Async, async, cancel, poll, wait, withAsync)
30+
import Control.Concurrent.Async (Async, cancel, poll, wait, withAsync)
3131
import Control.Exception (AsyncException (..), throwIO)
32-
import Control.Exception.Safe (handleAsync)
32+
import Control.Exception.Safe (handleAsync, uninterruptibleMask_)
3333
import Control.Monad.Except (MonadError (..))
3434
import Data.Bits (toIntegralSized)
3535
import Data.ByteString qualified as BS
@@ -415,7 +415,7 @@ verifyRepo
415415

416416
progressRef <- newIORef $ initVerifyProgress (map snd toScan)
417417
domainsReturned429Ref <- newIORef S.empty
418-
accumulated <- loopAsyncUntil (printer progressRef) do
418+
accumulated <- withAsync (printer progressRef) $ \_ ->
419419
forConcurrentlyCaching toScan ifExternalThenCache $ \(file, ref) ->
420420
verifyReference config mode domainsReturned429Ref progressRef repoInfo file ref
421421
case accumulated of
@@ -436,14 +436,15 @@ verifyRepo
436436
printer progressRef = do
437437
posixTime <- getPOSIXTime <&> posixTimeToTimeSecond
438438
progress <- atomicModifyIORef' progressRef $ \VerifyProgress{..} ->
439-
let prog = VerifyProgress{ vrExternal =
440-
checkTaskTimestamp posixTime vrExternal
441-
, ..
442-
}
439+
let prog = VerifyProgress
440+
{ vrExternal = checkTaskTimestamp posixTime vrExternal
441+
, ..
442+
}
443443
in (prog, prog)
444-
reprintAnalyseProgress rw mode posixTime progress
444+
uninterruptibleMask_ $ reprintAnalyseProgress rw mode posixTime progress
445445
-- Slight pause so we're not refreshing the progress bar more often than needed.
446446
threadDelay (ms 100)
447+
printer progressRef
447448

448449
ifExternalThenCache :: (a, Reference) -> NeedsCaching Text
449450
ifExternalThenCache (_, Reference{..}) =
@@ -825,28 +826,3 @@ checkExternalResource followed config@Config{..} link
825826
pure ()
826827
where
827828
handler = if secure then withFTPS else withFTP
828-
829-
----------------------------------------------------------------------------
830-
-- Helpers
831-
----------------------------------------------------------------------------
832-
833-
-- | @loopAsyncUntil ma mb@ will continually run @ma@ until @mb@ throws an exception or returns.
834-
-- Once it does, it'll wait for @ma@ to finish running one last time and then return.
835-
--
836-
-- See #163 to read more on why it's important to let @ma@ finish cleanly.
837-
-- * https://github.com/serokell/xrefcheck/issues/162
838-
-- * https://github.com/serokell/xrefcheck/pull/163
839-
loopAsyncUntil :: forall a b. IO a -> IO b -> IO b
840-
loopAsyncUntil loopingAction action =
841-
mask $ \restore -> do
842-
shouldLoop <- newIORef True
843-
loopingActionAsync <- async $ restore $ loopingAction' shouldLoop
844-
restore action `finally` do
845-
writeIORef shouldLoop False
846-
wait loopingActionAsync
847-
where
848-
loopingAction' :: IORef Bool -> IO ()
849-
loopingAction' shouldLoop = do
850-
whenM (readIORef shouldLoop) do
851-
void loopingAction
852-
loopingAction' shouldLoop

0 commit comments

Comments
 (0)