Как перехватить асинхронные исключения с помощью библиотеки безопасных исключений? - PullRequest
0 голосов
/ 29 мая 2018

Я пытаюсь погрузиться в создание параллельного и надежного кода с помощью 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 рекомендуется , или есть другой способ справиться с такими ситуациями, которые я не обнаружил?

1 Ответ

0 голосов
/ 29 мая 2018

Обратите внимание, что Control.Exception.Safe.throwTo включает синхронные исключения в AsyncExceptionWrapper, а IOError является синхронным.(Я понятия не имею, почему такая упаковка необходима, в любом случае вы никогда не должны генерировать синхронные исключения асинхронно.)

Чтобы ваш код работал, вы должны либо перехватить AsyncExceptionWrapper, либо использовать Control.Exception.throwTo.Но на самом деле я не совсем понимаю, что вы пытаетесь сделать, скорее всего, вы слишком усложняете вещи.

...