Я пытаюсь погрузиться в создание параллельного и надежного кода с помощью Haskell, и было рекомендовано использовать библиотеки safe-exception * и async .Однако мне трудно понять, как обрабатывать нефатальные ошибки, возникающие в результате действия async
.
Например, если существует простой цикл, который проверяет сетевой ресурс каждые n секунд, имеет смысл остановить это, используя функцию cancel
, которая вызовет AsyncCancelled
исключение, которое будет выброшено в отдельном потоке.Конечно, также существует вероятность того, что IOError
будет выброшено изнутри потока из-за разрыва сети или какой-либо другой проблемы.В зависимости от типа исключения и данных, которые он содержит, я хотел бы контролировать, игнорирует ли отдельный поток исключение, выполняет ли какое-либо действие, останавливает или вызывает исключение в основном потоке.
С помощью безопасногобиблиотека исключений, единственные функции, которые могут сделать это, - catchAsync
и другие подобные, которые помечены как опасные в документации.Кроме этого, в асинхронной библиотеке есть waitCatch
, но функция fromException
всегда возвращает Nothing
, когда я пытаюсь извлечь IOError
:
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Concurrent.Async
import Control.Concurrent hiding (throwTo)
import Control.Exception.Safe
import Control.Monad
import System.IO
import System.IO.Error hiding (catchIOError)
main = do
hSetBuffering stdin NoBuffering
putStrLn "Press any key to continue..."
a <- async runLoop
async $ hWaitForInput stdin (-1) *>
throwTo (asyncThreadId a) (userError "error")
waitCatch a >>= either handler nothing
where
printThenWait i = putStr (show i ++ " ") *> threadDelay 1000000
runLoop = sequence_ $ printThenWait <$> [1..]
nothing _ = pure ()
handler e
| Just (e' :: IOError) <- fromException e =
putStrLn "It's an IOError!"
| (Nothing :: Maybe IOError) <- fromException e =
putStrLn "We got Nothing!"
Я немного запуталсяоб опасности восстановления после асинхронных исключений, особенно когда стандартные функции, такие как cancel
, вызывают их выброс, и я не знаю, каков будет рекомендуемый способ их обработки при использовании этих двух библиотек.Это тот случай, когда catchAsync
рекомендуется , или есть другой способ справиться с такими ситуациями, которые я не обнаружил?