0

我正在尝试在码头上运行基于http4s的 webapp 。http4s 库提供了AsyncHttp4sServlet[IO]类来扩展,我使用如下:

class UserSvcServlet
    extends AsyncHttp4sServlet[IO](
      service = UserSvcServer.start,
      servletIo = BlockingServletIo(4096, Blocker.liftExecutorService(Executors.newCachedThreadPool())),
      serviceErrorHandler = DefaultServiceErrorHandler
    )

正如您在该service属性上看到的,我提供了具有以下实现的 http 服务:

def start[F[_]: ConcurrentEffect: ContextShift: Sync: Timer]: HttpApp[F] =
for {

  a <- EnvironmentLoader.db.load[F].map(create_transactor)
  b <- EnvironmentLoader.cors.load[F].map(origin)
       http = Logger.httpApp(true, true)(CORS(UserRoutes(UserProgram(LiveUserQuery.make(a))).routes, b).orNotFound)
} yield http

start方法应该返回HttpApp[F],但不幸的是for块返回F[Http[F]]。但是最后F将是一种IO类型。

这是 的定义HttpApp[F]

type Http[F[_], G[_]] = Kleisli[F, Request[G], Response[G]]  

两者EnvironmentLoader.db.load[F].map(create_transactor)EnvironmentLoader.cors.load[F].map(origin)都在它们的上下文中F,它们加载环境变量。为了加载环境变量,我使用库https://cir.is/

我知道,不可能Http[F]脱离上下文F。我必须在这里重组代码以使其工作吗?

更新

一种可能的解决方法是:

class UserSvcServlet
    extends AsyncHttp4sServlet[IO](
      service = UserSvcServer.start[IO].unsafeRunSync(),
      servletIo = BlockingServletIo(4096, Blocker.liftExecutorService(Executors.newCachedThreadPool())),
      serviceErrorHandler = DefaultServiceErrorHandler
    )

它很丑,但它有效。

4

1 回答 1

4

是的,你必须。

当你有F[Http[F]]你应该将它组合到你的 IO 程序中:

for {
  dep1 <- createDependency1
  dep1 <- createDependency2
  http <- createHttp // : F[HttpApp[F]] = F[Request[F] => F[Response[F]]]
                     // or "use side effects to create a function that
                     // will take side-effecting request to create
                     // recipe for side-effecting response" (e.g.
                     // reading from stream to server and returning
                     // a stream from server)
  dep4 =  needHttp(http)
  ...
} yield ...

在您的代码中,从F[HttpApp[F]]to的更改HttpApp[F]似乎实际上只需要更改:

http = ...

进入

http <- ...

哪种建议,您对代码的作用没有给予足够的关注。

于 2020-07-04T10:56:40.443 回答