3

I am trying to create webapp with http4s that is based on Http4sServlet. The following code does not compile:

import cats.effect._
import org.http4s.servlet.BlockingServletIo
import org.http4s.servlet.Http4sServlet
import scala.concurrent.ExecutionContext.global
import org.http4s.implicits._


class UserSvcServlet
  extends Http4sServlet[IO](service = UserSvcServer.start
    , servletIo = BlockingServletIo(4096, Blocker.liftExecutionContext(global)))(IOApp)

the error message:

[error] /home/developer/scala/user-svc/src/main/scala/io/databaker/UserSvcServlet.scala:12:54: Cannot find implicit value for ConcurrentEffect[[+A]cats.effect.IO[A]].
[error] Building this implicit value might depend on having an implicit
[error] s.c.ExecutionContext in scope, a Scheduler, a ContextShift[[+A]cats.effect.IO[A]]
[error] or some equivalent type.
[error]   extends Http4sServlet[IO]( service = UserSvcServer.stream
[error]                                                      ^
[error] /home/developer/scala/user-svc/src/main/scala/io/databaker/UserSvcServlet.scala:13:36: Cannot find an implicit value for ContextShift[[+A]cats.effect.IO[A]]:
[error] * import ContextShift[[+A]cats.effect.IO[A]] from your effects library
[error] * if using IO, use cats.effect.IOApp or build one with cats.effect.IO.contextShift
[error]     , servletIo = BlockingServletIo(4096, Blocker.liftExecutionContext(global)))
[error]                                    ^
[error] two errors found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 1 s, completed May 29, 2020, 8:45:00 PM

The UserSvcServer is implemented as follows:

import org.http4s.HttpApp
import cats.effect.{ConcurrentEffect, ContextShift, Timer}
import org.http4s.implicits._
import org.http4s.server.middleware.Logger


object UserSvcServer {

  def start[F[_] : ConcurrentEffect](implicit T: Timer[F], C: ContextShift[F]): HttpApp[F] = {
    val helloWorldAlg = HelloWorld.impl[F]
    val httpApp = UserSvcRoutes.helloWorldRoutes[F](helloWorldAlg).orNotFound
    Logger.httpApp(true, true)(httpApp)
  }
}

How can I import ContextShift implicitly?

4

1 回答 1

4

上下文转移只是猫的包装ExecutionContext。您可以按照文档中的说明明确创建一个:

implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)

您通常在应用程序的入口点创建一个上下文转换(可能在 main 方法中)。

如果您的应用程序使用IOApp来自猫的效果,那么它已经隐含了 contextShift 的范围。它将使用执行上下文,其线程数等于您计算机的可用处理器。

如果您想在应用程序中使用创建的 contextShift “更深”,您可以将其作为隐式参数传递:

def doSomething(implicit cs: ContextShift[IO]): IO[Unit] = ???

因此,为了使您的代码正常工作,您需要确保方法或类调用的构造函数UserSvcServlet具有隐含的 contextShift: (implicit cs: ContextShift[IO])

您也可以将其放在单独的对象中:

object AppContextShift {

  implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
  implicit val t: Timer[IO] = IO.timer(ExecutionContext.global) //you will probably also need timer eventually

}

然后你可以在需要 contextShift 时导入它:

import AppContextShift._

顺便说一句,为 Blocker 使用全局执行上下文并不是一个好主意。Blocked 用于阻塞操作,使用它ExecutionContext.global可能会导致应用程序中的线程饥饿。

最常见的方法是使用从缓存线程池创建的阻塞器:

Blocker.liftExecutorService(Executors.newCachedThreadPool())

于 2020-05-29T19:58:18.877 回答