在Haskell中执行一系列操作时的异常处理

3

以下是我希望加入错误处理的代码概述。

worldHandler :: ProcessState -> JobCount -> IO ()
worldHandler world jCount = do
   putStrLn "Entered worldHandler"
   jcount <- takeMVar jCount
   if jcount > 0
      then incrementThenDone jcount
      else doJobProcessing jcount
      where incrementThenDone jcount = do
                putMVar jCount (jcount+1)


            doJobProcessing jcount = do
                putMVar jCount (jcount+1)
                preProcess world
                initiateJob world
                makeChart world

这里是main函数。
main :: IO ()
main = do
    world <- (newEmptyMVar :: IO ProcessState)
    jCount <- (newMVar 0 :: IO JobCount)
    installHandler userDefinedSignal1 (Catch $ worldHandler world jCount) Nothing
    forever (threadDelay 10000)

函数preProcessinitiateJobmakeChart是我需要关注错误的地方。如果这些函数中的任何一个失败,我就会减少jCount并调用logError。然后,如果jCount > 0,再次开始这三个函数。如果jCount == 0,则继续等待下一个信号。
每个这样的函数都将启动另一个进程,readProcessWithExitCode看起来是我想要的。然后我将使用退出代码来确定成功或失败。
我想到的一个方法是创建一个[preProcess,initiateJob,makeChart]。然后,我将在此列表上映射函数jobProcessor。如果其中一个函数从它们调用的程序接收到失败消息,我可以生成一个异常,并且映射将停止映射整个列表。
这种方法行得通吗?
欢迎提出关于如何处理此问题的一般思路以及任何相关问题。

我不明白你在这里尝试做什么 - jCount代表什么?它不会无限增加吗? - bdonlan
不,代码中没有包含对jCount的递减操作,无论是作业完成还是出现异常。 jCount将跟踪需要处理的作业。如果它> 0,则增量表示另一个作业。在抛出异常或完成作业时,将再次检查jCount。如果> 0,则会通过相同的三个处理函数进行处理。 - user1198582
为什么需要跟踪计数呢?虽然worldHandler知道它是否有尚未完成的任务,但我在这里没有看到任何作业队列或线程池... - bdonlan
也许他正在使用 jCount 作为穷人版的 BoundedChan - Thomas M. DuBuisson
bdolan:我这样做是为了考虑到在作业进行时可能会捕获到信号的情况。这似乎是最简单的方法。 - user1198582
1个回答

0

现在我们只看这个序列,暂时不考虑计数。

preProcess world
initiateJob world
makeChart world

作为一个顶级函数,它看起来会像这样:
doJobProcessing :: ProcessState -> IO ()
doJobProcessing world = do
    preProcess world
    initiateJob world
    makeChart world

编程相关内容。如果其中任何一个失败,我们希望中断执行流程,并(可能)重新启动。

可以使用Haskell-exceptions,也可以不使用。首先让我们看一下没有异常的解决方案,因为它也适用于非IO代码。我不知道你的类型实际上是什么,所以让我们假设它们都是

preProcess, initiateJob, makeChart :: ProcessState -> IO ExitCode

现在这里是可怕且丑陋的显而易见的方法(总是一个好的起点)

doJobProcessing :: ProcessState -> IO ()
doJobProcessing world = do
    preProcessStatus <- preProcess world
    if preProcessStatus /= ExitSuccess
      then jobFail world
      else do
        initiateJobStatus <- initiateJob world
        if initiateJobStatus /= ExitSuccess
          then jobFail world
          else do
            makeChartStatus <- makeChart world
            if makeChartStatus /= ExitSuccess
              then jobFail world
              else return ()  ---success!!!

jobFail :: ProcessState -> IO ()
jobFail world = do
    --some test involving jCount
    if --test says to try again
      then do
        --inc/dec jCount
        doJobProcessing world
      else do
        -- nothing; we give up
        return ()

这个行为符合你的期望吗?(如果makeChart甚至都失败了,它会从preProcess重新开始尝试。)如果是的话,我将展示如何使用纯Haskell抽象和/或异常来简化它。(如果你只想让preProcess、initiateJob和makeChart中的每一个重新启动自己,我也可以展示一种方法来实现。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接