gpt4 book ai didi

haskell - 为什么 `catch` 没有捕捉到这个异常?

转载 作者:行者123 更新时间:2023-12-02 00:20:48 25 4
gpt4 key购买 nike

我有一个 Servant 应用程序和一个在数据库中创建记录的端点,然后尝试在 S3 位置之间复制文件。如果复制失败,我想回滚事务。我有这个运算符

{-# LANGUAGE TemplateHaskell #-}    

import Control.Monad.Catch
import Control.Monad.Except
import Control.Monad.Logger

(<??)
:: (MonadError e m, MonadCatch m, MonadLogger m)
=> e
-> m a
-> m a
(<??) err a = a `catchAll` (\e -> $(logErrorSH) e >> throwError err)
infixr 0 <??

捕获所有异常,记录异常的性质,然后抛出(在我的例子中,因为我的 App 类型有一个 MonadError ServantErr 的实例)一个 ServantErr .

我的处理程序是这样的:

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad
import Control.Monad.Catch
import Control.Monad.IO.Class
import qualified Network.AWS as AWS
import Servant

import App.Types
import App.Db


copy :: Copy -> App Text
copy (Copy user bucket srcKey tgtKey) = do
err400 <?? runDb (insertRecord $ User user bucket srcKey tgtKey)

catch (err500 <?? liftIO $ do
env <- AWS.newEnv AWS.Discover
void . AWS.runResourceT . AWS.runAWS env $ copyFiles bucket srcKey tgtKey
return "OK") (\(e :: ServantErr) -> rollback e user)
where rollback e u = runDb (deleteRecord u) >> throwError e

为了测试逻辑,我移动了我的 AWS 凭证文件,期望内部 AWS 操作会抛出 InvalidFileError , 然后 (<??)会将其转换为 ServantErr , 然后 catch会捕获这个 ServantErr并执行回滚功能。相反发生的是插入成功,InvalidFileError被记录,但回滚永远不会发生(即,记录在执行后仍然存在于数据库中)。这deleteRecord函数已在其他地方成功使用,因此我可以确定它的定义不是问题。

知道是什么原因造成的吗?

最佳答案

如果您的 App 类型最终是 ExceptT ,问题可能是 ExceptTMonadErrorMonadCatch 实例不匹配:

  • MonadError 实例抛出错误作为 ExceptT e 中的 e
  • MonadCatch 实例捕获底层 monad 中的异常,而不是 ExceptTe 错误。

instance definition MonadCatch (ExceptT e m) 是:

-- | Catches exceptions from the base monad.
instance MonadCatch m => MonadCatch (ExceptT e m) where
catch (ExceptT m) f = ExceptT $ catch m (runExceptT . f)

ServantErr有一个 Exception实例,因此它可以同时抛出。


编辑:“异常”类 MonadMask 提供了 onError函数,即使对于 ExceptT 也是表现良好的:它在 ExceptT e 异常 常规异常的情况下运行清理操作:

Run an action only if an error is thrown in the main action. Unlike onException, this works with every kind of error, not just exceptions. For example, if f is an ExceptT computation which aborts with a Left, the computation onError f g will execute g, while onException f g will not.

在处理回滚方面,这是比 catch 更好的选择。

关于haskell - 为什么 `catch` 没有捕捉到这个异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55434021/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com