Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot find an implicit value for ContextShift[cats.effect.IO] in http4s version 19.0.0

I have a http4s project which uses ciris for configuration management.

The project is in github here.

libraryDependencies ++= Seq(
  "is.cir" %% "ciris-cats",
  "is.cir" %% "ciris-cats-effect",
  "is.cir" %% "ciris-core",
  "is.cir" %% "ciris-enumeratum",
  "is.cir" %% "ciris-refined"
).map(_ % "0.12.1")

libraryDependencies ++= Seq(
  "org.http4s" %% "http4s-dsl",
  "org.http4s" %% "http4s-blaze-server"
).map(_ % "0.18.18")

libraryDependencies ++= Seq(
  "com.ovoenergy" %% "ciris-kubernetes" % "0.5",
  "org.typelevel" %% "kittens" % "1.2.0",
  "eu.timepit" %% "refined-cats" % "0.9.3"
)

When I compile my project I get below error here

    [info] Compiling 12 Scala sources to /Users/rajkumar.natarajan/Documents/Coding/OS/ciris-example/target/scala-2.12/classes ...
    [error] /Users/rajkumar.natarajan/Documents/Coding/OS/ciris-example/src/main/scala/is/cir/example/application/Http4sApi.scala:24:68: Cannot find an implicit value for ContextShift[cats.effect.IO]:
    [error] * import ContextShift[cats.effect.IO] from your effects library
    [error] * if using IO, use cats.effect.IOApp or build one with cats.effect.IO.contextShift
    [error]   implicit val ioConcurrentEffect: Concurrent[IO] = cats.effect.IO.ioConcurrentEffect
    [error]                                                                    ^
    [error] /Users/rajkumar.natarajan/Documents/Coding/OS/ciris-example/src/main/scala/is/cir/example/application/Http4sApi.scala:43:69: type mismatch;
    [error]  found   : (ec: scala.concurrent.ExecutionContext, sc: java.util.concurrent.ScheduledExecutorService)cats.effect.Timer[cats.effect.IO] <and> (ec: scala.concurrent.ExecutionContext)cats.effect.Timer[cats.effect.IO]
    [error]  required: cats.effect.Timer[cats.effect.IO]
    [error]         Timeout(finite)(service)(ioConcurrentEffect, cats.effect.IO.timer)
    [error]                                                                     ^

The reason is I'm missing implicit parameter which needed by the function here The error tells me to use use cats.effect.IOApp or build one with cats.effect.IO.contextShift but couldn't find cats.effect.IOApp or cats.effect.IO.contextShift

Any Help is appreciated.

like image 401
Rajkumar Natarajan Avatar asked Jan 07 '19 01:01

Rajkumar Natarajan


1 Answers

There are several popular usages of implicit and one of them is to to pass some "context" information. The code you look at is a classical example of this usage.

When you do "timeout" there are 2 things you need to decide on:

  • where (on which thread) the main job will be run on
  • where (on which thread) the timer will be fired on as in JVM world (unlike JavaScript for example) there is no standard timer.

The important thing about those parameters are that on the one hand they are essential to the job but on the other hand they are only supportive to the main parameter. Another thing is that you probably want to have just one (or very few) global objects that you use everywhere for those things. This is what makes them context and this is why they are passed implicitly.

Now you have a choice of where to get them:

  • make them your context as well, i.e. force the caller to pass them to you (also implicitly
  • create your own instances

This choice is not a trivial design decision and depends on how are you going to use your API. Typically the correct choice is the first one - make them your context. In that way you allow the caller to setup the context the way it want to (for example, should Timer and Concurrent use the same thread pool or different ones?). Sometimes it is OK to create your own independent context. Or to wrap another context you received from outside into something specific to you.

Assuming you want to wrap the outer context at the boundary of your Http4sApi, you may write a code like this:

final case class Http4sApi()(implicit executionContext: ExecutionContext) extends HttpApiAlg[IO] {
  // create IO-specific context from the executionContext
  private implicit val cs = IO.contextShift(executionContext)
  private implicit val timer = IO.timer(executionContext)

Then you can write just

def withTimeout(timeout: Duration)(service: HttpService[IO]): HttpService[IO] = timeout match {
    case finite: FiniteDuration => Timeout(finite)(service)
    case _                      => service
}

and it should compile.

like image 163
SergGr Avatar answered Oct 06 '22 23:10

SergGr