question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Ember client hangs on large responses when F[_] is a Kleisli

See original GitHub issue

I was experimenting with integrating the http4s client with Natchez tracing, and I ran into a bug with Ember. When I converted the F[_] to be the Kleisli[....] that Natchez needs, the ember client started to hang on requests that were more than one chunk. I don’t know if it’s failing to terminate after the stream is over, or if it is failing to proceed past the second chunk; I’ve only been able to test it with 2 chunk responses.

Example Code

EmberBroken.scala

package emberbroken

import cats._
import cats.data.Kleisli
import cats.implicits._
import cats.effect._
import cats.effect.implicits._
import natchez.{EntryPoint, Span, Trace}
import org.http4s._
import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.implicits._
//import org.http4s.client.blaze.BlazeClientBuilder
import org.http4s.ember.client.EmberClientBuilder

import scala.concurrent.ExecutionContext

object EmberBroken extends IOApp {
  // This will always work
//  override def run(args: List[String]): IO[ExitCode] = runIO
  
  // This will fail when the stream has multiple chunks
  override def run(args: List[String]): IO[ExitCode] = runTraced

  def runIO = runF[IO]
  def runTraced = entryPoint[IO].use { ep =>
    ep.root("Testing Ember App").use { root =>
      runF[Kleisli[IO, Span[IO], *]].run(root)
    }
  }

  def runF[F[_]: Concurrent: Timer: ContextShift]: F[ExitCode] =
    EmberClientBuilder.default[F].build
    .use { c =>
      c.get((uri"https://baconipsum.com/api/")
        .withQueryParam("type", "meat-and-filler")
        .withQueryParam("paras", "100") // Set this to something smaller and it works
        .withQueryParam("format", "text")
      ) {
        res => Sync[F].delay { println("Got a response") } *>
          res.bodyText
            .evalTap(text => Sync[F].delay { println("Have a chunk")})
            .compile.drain
      }
        .flatTap(_ => Sync[F].delay { println("fetched") }) // Not printed when response is too large
        .as(ExitCode.Success)
    }

  def entryPoint[F[_]: Sync]: Resource[F, EntryPoint[F]] = {
    import natchez.jaeger.Jaeger
    import io.jaegertracing.Configuration.SamplerConfiguration
    import io.jaegertracing.Configuration.ReporterConfiguration
    Jaeger.entryPoint[F]("natchez-example") { c =>
      Sync[F].delay {
        c.withSampler(SamplerConfiguration.fromEnv)
          .withReporter(ReporterConfiguration.fromEnv)
          .getTracer
      }
    }
  }
}

build.sbt

name := "emberbroken"

scalaVersion := "2.13.2" // Also supports 2.12.x

val http4sVersion = "0.21.6"

// Only necessary for SNAPSHOT releases
resolvers += Resolver.sonatypeRepo("snapshots")

//scalacOptions += "-Ypartial-unification"

libraryDependencies += "org.http4s" %% "http4s-dsl" % http4sVersion
libraryDependencies += "org.http4s" %% "http4s-blaze-client" % http4sVersion
libraryDependencies += "org.http4s" %% "http4s-ember-client" % http4sVersion
libraryDependencies += "org.tpolecat"  %% "natchez-jaeger" % "0.0.11"

addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full)

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
gatorcsecommented, Apr 12, 2021

@rossabaker Fixed, seems to be fixed as of 0.21.7, the very next version after my initial test. Also confirmed works in 0.22.0-M7

1reaction
gatorcsecommented, Jul 6, 2020

yeah, entryPoint gives a Resource of EntryPoint. The entryPoint code is copied directly from the natchez examples

Read more comments on GitHub >

github_iconTop Results From Across the Web

http4s/http4s - Gitter
I need to develop an access log for my app, logging request and response details. ... Kleisli { req: Request[F] => OptionT( for...
Read more >
Changelog
Update http4s-circe, http4s-ember-client to 0.23.15 in series/0.23 by ... to work on Kleisli[F, A, Response[G]] given Concurrent[F] and Timer[F] .
Read more >
Kleisli
What type class instances it has tends to depend on what instances the F[_] has. For instance, Kleisli[F, A, B] has a Functor...
Read more >
Read Pure functional HTTP APIs in Scala
Also I send a big thank you to all the nice people from the Scala community which I've had the pleasure to meet....
Read more >
ploeh blog danish software design
In a distributed system where a client posts a document to a service, ... Instead, I decided to call the type Validated<F, S>...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found