Help me define an http4s using ZLayers. I'm learning and I'm confused. I'd like to factor out the http server as a component. But I don't know how to compose the ZManageds and the the ZLayers so that it would compile.
Also does it makes sense to create a layer that requires a Runtime[ZEnv]
? Or does that make more sense to create a layer that requires a ZEnv
and generate the runtime for it.
object HttpServer {
def createHttp4Server: ZManaged[Runtime[ZEnv], Throwable, Server] =
ZManaged.accessManaged { implicit runtime: Runtime[ZEnv] =>
BlazeServerBuilder[Task](runtime.platform.executor.asEC)
.bindHttp(8080, "localhost")
.withHttpApp(Routes.helloWorldService)
.resource
.toManagedZIO
}
def createHttp4Layer: ZLayer[RuntimeLayer, Throwable, Http4ServerLayer] =
ZLayer.succeed(createHttp4Server)
}
object Routes {
val helloWorldService = ...
}
package object simple {
type Http4ServerLayer = Has[ZManaged[Runtime[ZEnv], Throwable, Server]]
type RuntimeLayer = Has[Runtime[ZEnv]]
}
I don't know how to access the ZManaged[..., ..., Server]
from the Layer
in here in the main.
I don't understand the access
methods completely.
object ItsAren extends App {
def run(args: List[String]): URIO[ZEnv, ExitCode] = {
val toProvide: ZIO[Http4ServerLayer, Nothing, ExitCode] =
ZIO
.accessM[Http4ServerLayer](_.get.useForever) //compile error
.as(ExitCode.success)
.catchAll(ZIO.succeed(ExitCode.failure))
val runtimeLayer: ZLayer[Any, Nothing, RuntimeLayer] = ZLayer.succeed(Runtime.default)
val http4Layer: ZLayer[RuntimeLayer, Throwable, Http4ServerLayer] = HttpServer.createHttp4Layer
val fullLayer: ZLayer[Any, Throwable, Http4ServerLayer] = runtimeLayer >>> http4Layer
val provided = toProvide.provideCustomLayer(fullLayer)
provided //compile error
}
}
type mismatch
found : ZIO[Runtime[ZEnv], Throwable, Nothing]
required: ZIO[Http4ServerLayer, ?, ?]
also at the bottom, but that's lower importance
found : ZIO[ZEnv, Throwable, ExitCode]
required: URIO[ZEnv, ExitCode]
Same thing in a PR, feel free to comment https://github.com/kovacshuni/itsaren/pull/1
Solution is that a ZLayer when holding a Managed, is a Managed itself. So when something is running on a layer like this, the included Managed will be used through that time. So if you run a
ZIO.never
on a layer, the server will be kept alive.To build the layer itself was another trick to use
fromManaged
. And thecreateHttp4Server
requires aZEnv
only, no point in requiring aRuntime
I admit now.ZManaged.runtime
is another trick they have for not to useZManaged.accessManaged { implicit runtime: Runtime[ZEnv] =>
.Full solution https://github.com/kovacshuni/zio-http4s-zlayer-example