3

我写了一个函数

app :: Request -> H.Session H.Postgres IO Response

它接受 Web 请求并构建响应(根据需要咨询数据库)。为了实际发送响应,我做了一个包装器

runApp :: H.Postgres -> H.SessionSettings -> Application
runApp pg sess req respond =
  respond =<< H.session pg sess (app req)

我将此函数传递给WarprunSettings永久循环并处理请求:

runSettings appSettings $ runApp pgSettings sessSettings

然而,这真的很糟糕,因为它为每个请求创建一个新会话,这违背了连接池和准备好的语句的目的。

我想打电话给runSettings里面H.session而不是反过来。但是runSettings有一个签名Settings -> Application -> IO (),一旦进入IO我就无法访问会话。有没有办法回到里面Session b m r

这是来自私人电子邮件的问题的转贴。

4

1 回答 1

3

是的,在您的示例中,您为每个请求创建一个新会话,这是不可接受的。

首先,Session它只是 reader monad transformer 的别名,它使您可以直接访问池。所以你总是可以这样做:

session postgresSettings sessionSettings $ do
  -- session' :: H.Session b m r -> m r
  session' <- flip runReaderT <$> ask
  let runApp request respond = 
        respond =<< session' (app request)
  liftIO $ do
    -- run warp here 

其次,ReaderT有一个MonadBaseControl实例,用于类似的模式。

于 2014-11-17T15:14:10.290 回答