我正在构建一个仆人应用程序,该应用程序使用通过获取 url 开始的摇动生成报告。直到请求记录东西,这就像一个魅力,但现在我遇到了一个问题。
一个处理程序start
开始生成报告 - 因为这可能需要相当长的时间 - 我立即返回 200,并生成一个进程来完成实际工作,日志记录由logging-effect
.
我的处理程序的简化版本start
如下所示
start :: IO () -> App ()
start mkReport = do
logInfo $ PP.text "Report generation started"
_ <- liftIO . forkIO $ catch mkReport caught
where caught e = do logError $ PP.text "Report generation crashed: " <>
{-^^^^^^^-} (PP.text . T.pack $ displayException e)
cleanup
return ()
App
是MonadLog (WithTimestamp (WithSeverity Doc))
- 所以logInfo
工作正常。✔</p>
准确地说App
是以下新类型:
newtype App a =
App { _runApp :: ReaderT Environment (ExceptT ServantErr
(LoggingT (WithTimestamp (WithSeverity Doc)) IO)) a
} deriving ( Functor, Applicative, Monad, MonadReader Environment,
, MonadError ServantErr, MonadLog (WithTimestamp (WithSeverity Doc)))
但是当我尝试logError
在部件内部调用时caught
- 除了cleanup
删除生成/临时文件的操作之外,我得到一个编译器错误。✘</p>
No instance for MonadLog (WithSeverity Doc) IO arising from a use of 'logError'...
这是正确的,没有这样的实例IO
,谢谢 ghc 告诉我这一点并且在运行时没有崩溃!
这些是我正在经历的想法-也许有人看到了错误的假设:
- 我必须使用
forkIO
fork 报告生成? - 如果有类似的东西,
forkIOish :: MonadIO m => m () -> m ThreadId
它catchIsh :: (MonadIO m, Exception e) => m a -> (e -> m a) -> m a
会帮助我吗?- 我认为是的 - 在我的情况下,我可以在内部liftIO
调用时进行清理和 mkReport 部分。logError
App
- 有没有办法在提升的部分中“解除”单子变压器堆栈的属性?