by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 12:50
    scala-steward opened #443
  • 12:49
    scala-steward opened #3644
  • 12:49
    scala-steward opened #3643
  • 12:47
    scala-steward opened #433
  • 02:38
    ChristopherDavenport commented #330
  • 02:31
    ChristopherDavenport commented #3619
  • 02:30
    ChristopherDavenport commented #330
  • 02:29
    ChristopherDavenport commented #330
  • 00:22
    rossabaker commented #3619
  • 00:07
    rossabaker commented #330
  • Aug 12 22:32
    ChristopherDavenport commented #330
  • Aug 12 14:22
    rossabaker milestoned #3605
  • Aug 12 14:18
    kailuowang synchronize #3641
  • Aug 12 13:23
    kailuowang synchronize #3641
  • Aug 12 08:00
    satorg synchronize #3609
  • Aug 12 05:02
    rossabaker commented #330
  • Aug 12 02:19
    rossabaker labeled #3641
  • Aug 12 02:19
    rossabaker labeled #3641
  • Aug 11 22:15
    gordon-rennie closed #3642
  • Aug 11 22:15
    gordon-rennie commented #3642
Otto Chrons
@ochrons
@paul-snively ok, sounds sensible!
the TLS/SSL stuff looks like PITA on the server side, so happy to outsource that to nginx :smile:
we run services under Kubernetes, so requires some additional setup to get the containers properly configured
@nafg thx for the tip!
Gavin Bisesi
@Daenyth
@dabd It would probably be easier to operate on your HttpApp before calling orNotFound
Dario Abdulrehman
@dabd
@Daenyth I have an HttpRoutes[F] not an HttpApp, can you please elaborate a bit?
Gavin Bisesi
@Daenyth
IIRC you call orNotFound on an HttpApp to convert it into HttpRoutes
Both of those are aliases for Kleisli
Dario Abdulrehman
@dabd
how would that help me get the Kleisli I need for the timeout middleware?
Gavin Bisesi
@Daenyth
because it IS a Kleisli that fits that input shape
Lucio Biondi
@sherpair
@chrons In case you still want to configure SSL for http4s I have a a full-blown setup at https://github.com/sherpair/weather4s/
All SSL things are in shared, I can add more details if you need.
Paul Snively
@paul-snively
@ochrons: In Kubernetes, I'd expect TLS termination to be handled by your Ingress controller anyway.
Otto Chrons
@ochrons
yea, so I've learned from our devops friend :D
Ender Tunc
@endertunc_gitlab
Hey all. does this peace of code look fine. I mean, I was just trying to make it work so I am not sure if I am doing something horrible (like never use IO.never or do it like this because of the reasons etc). I just wanted to get quick feedback. Thanks in advance!
object CarAdvertServer extends IOApp {
  override def run(args: List[String]): IO[ExitCode] = new HttpServer[IO].server().use(_ => IO.never).as(ExitCode.Success)
}

class HttpServer[F[_]: ConcurrentEffect: ContextShift: Timer] {
  implicit val runner: Sync[F]         = Sync[F]
  private val dbConfig: DatabaseConfig = ???

  def server(): Resource[F, Server[F]] =
    for {
      connEc <- ExecutionContexts.fixedThreadPool[F](dbConfig.connections.poolSize)
      txnEc  <- ExecutionContexts.cachedThreadPool[F]
      flywayDatabaseMigrator = FlywayDatabaseMigrator[F]
      xa <- flywayDatabaseMigrator.dbTransactor(dbConfig, connEc, Blocker.liftExecutionContext(txnEc))
      carAdvertRepository = PostgresCarAdvertRepository[F](xa)
      carAdvertService    = CarAdvertService[F](carAdvertRepository)
      carAdvertRoutes = {
        implicit val httpErrorHandler: HttpErrorHandler[F] = new HttpErrorHandler[F]
        CarAdvertHttpRoutes[F](carAdvertService)
      }
      _ <- Resource.liftF(flywayDatabaseMigrator.migrate(xa))
      server <- BlazeServerBuilder[F]
        .bindHttp(9000, "0.0.0.0")
        .withHttpApp(carAdvertRoutes.routes.orNotFound)
        .resource
    } yield server

}
Cory Parent
@goedelsoup
looks sane to me, nothing too dissimilar from the ~8 http4s servers i am running
Colt Frederickson
@coltfred
Is there a blog post or documentation that talks about the best practices for thread pools with http4s and doobie? I'm creating fixed thread pools for connecting to the db and cached connection pools for the transaction connection pool. I'm using the global execution context when I build my blaze server. I'm seeing response times go through the roof under load without any real CPU usage at all. Does this sound reasonable? I'm using 10 db connections and haven't researched if they're all being used, yet. Basically trying to sanity check my baseline.
I guess the above question/answer implies that @goedelsoup is basically doing that as is @endertunc_gitlab .
Cory Parent
@goedelsoup
we're doing greenfield so i haven't optimized there. i'd love to see some real world experience there as well.
Dario Abdulrehman
@dabd
Hi I'm having some difficulty manipulating the Kleislis in the library. In the following example I'd like to use the Timeout middleware given some HttpRoutes. This should return a Kleisli. Then I want to go from this Kleisli back to HttpRoutes to pass to function f. I understand HttpRoutes is also a Kleisli but it takes an OptionT which makes it hard to make the transformation. @Daenyth mentioned yesterday it would be easy to operate on HttpApp but I didn't quite get it. Any help please?
import org.http4s.server.middleware.Timeout

def f(routes: HttpRoutes[IO]) = ???

def g(routes: HttpRoutes[IO]) = {
  val timeout = Timeout(0.milliseconds, ServiceUnavailable("time out"))(<how to pass routes here>)
  f(<how to go from timeout Kleisli back to HttpRoutes>)
}
Dimitar Georgiev
@dimitarg

seeing response times go through the roof under load without any real CPU usage at all.

@coltfred if you're not doing computation, that would indicate you're doing IO, so some possibilities are

  • your DB is the bottleneck
  • Something is doing blocking IO in your "global" execution context

You'll need to monitor your app to understand what the case is. That being said, your described setup of fixed thread pool for acquiring connections, cached thread pool for db work, a good connection pool (Hikari) and passing the "global/computation" thread pool to blaze is a standard setup which works. Blaze will not perform blocking IO on that pool

using 10 db connections

That's usually calculated depending on the number of cores and type of storage of the database server and also it's configuration, but in practice this number is fine (it's not outrageously high even for a smallish db server) (I tend to use 4, same magnitude)

Ender Tunc
@endertunc_gitlab

Hey all, the way I log trace log as follows at the moment.

    private val logger: Logger = LoggerFactory.getLogger(this.getClass)

    case GET -> Root / username =>
      for {
        user     <- userService.findUser(UserName(username))
        _        <- Sync[F].delay(logger.trace("Retrieving user [{}]", username))
        response <- user.fold(H.handle, x => Ok(x.asJson))
      } yield response

Is there a better way to do it (like more functional?)

Dimitar Georgiev
@dimitarg

@coltfred

I'm seeing response times go through the roof under load

Also I guess you need to define what "under load" means. For example, when I've done load tests against a DB-backed service, at some point I'll see response times start to grow exponentially, but that usually just shows that the load I'm exercising in that test is unrealistic.

I.e. if you're hitting a db-backed service continuously with 100000 concurrent actors without any backoff and your database has 2 physical cores, yes, you are going to see response times even higher that a well-configured http server response timeout, but that doesn't really surprise or say anything

Erlend Hamnaberg
@hamnis
@dabd The Timeout middleware takes two type constructors, so you can manipulate which Kleisli you get back. a HttpRoutes is a Kleisli fixed on OptionT[F], a HttpApp is fixed on F[_]
Dario Abdulrehman
@dabd
@hamnis sorry I'm still unable to understand how to pass the routes to the Timeout middleware. This works but it is ugly Timeout(0.milliseconds, ServiceUnavailable("time out"))(routes.orNotFound).mapF(f => OptionT(f.map(Option(_))))
There must be a simpler way?
Paul Snively
@paul-snively
@dabd: You should just be able to pass routes as-is.
@endertunc_gitlab: There are logging middlewares.
Ender Tunc
@endertunc_gitlab
@paul-snively I would like to do some extra logging as well in case of errors etc. I found there is a log4cats library. I'll give it a try! Thanks anyway ;)
Paul Snively
@paul-snively
@endertunc_gitlab: I would still implement it as a middleware.
Ender Tunc
@endertunc_gitlab
@paul-snively I am really really new so I don't know the capabilities of middlewares yet. Since you would prefer to use a middleware, I will take a look ;)
Dario Abdulrehman
@dabd
@hamnis @paul-snively it seems like mapK(OptionT.liftK)) is how to go from the Timeout middleware to HttpRoutes. It took me a good day of asking around to figure this out. So far my experience with http4s shows that without a very good understanding of all the cats abstractions it is pretty hard to use.
Paul Snively
@paul-snively
@dabd: I’m not sure what you mean by “from the Timeout middleware to HttpRoutes,” but I would say http4s is a relatively thin layer around fs2 and cats-effect, so yes, knowing them well is very helpful.
@dabd: Timeout is polymorphic in its Request and Response effect types, like all of http4s. OptionT[F, ?] is one effect type you can use, which is how HttpRoutes is defined.
Dario Abdulrehman
@dabd
@paul-snively In the snippet I posted above I wanted to pass the result of Timeoutwhich in my case is Kleisli[IO, Request[IO], Response[IO]] to a function that expects HttpRoutes[IO] which is a Kleisli[OptionT[IO, ?], Request[IO], Response[IO]]. It requires a natural transformation unless there is a simpler way.
Fabio Labella
@SystemFw
@dabd at a quick glance it seems like Timeout is polymorphic so it should work for both HttpRoutes and HttpApp without changes
let me give it a try
Paul Snively
@paul-snively
@dabd: I guess my question is, how do you find yourself starting with IO rather than OptionT[IO, ?]?
@SystemFw: I believe he’s saying he’s not wrapping an HttpRoutes in Timeout.
@SystemFw: But needs an HttpRoutes after.
Fabio Labella
@SystemFw
My understanding is that what's needed is applying Timeout to HttpRoutes, and currently the code is like orNotFound to go from HttpRoutes to HttpApp and then mapK with OptionT to get back to HttpRoutes, which I don't think it's necessary
object Ex {
  import cats.implicits._
  import cats.effect._
  import org.http4s._
  import org.http4s.server.middleware._

  def a[F[_]]: HttpRoutes[F] = ???
  def b[F[_]: Concurrent: Timer]: HttpRoutes[F] = Timeout(4.seconds)(a[F])
}
@dabd is this what you need?
Dario Abdulrehman
@dabd

@SystemFw my code looks like so

override def serverResource(routes: HttpRoutes[IO]): Resource[IO, Server[IO]] = {
  val errorResponse = ErrorResponse(List(ErrorResponse.Error("Response timed out")))

  super.serverResource(
    Timeout(0.milliseconds, ServiceUnavailable(errorResponse.asJson))(routes.orNotFound)
      .mapK(OptionT.liftK))
}

I am passing the output of Timeout to serverResource which takes HttpRoutes[IO]. Also I'm using the Timeout apply method that takes a custom response. Not sure if this affects type inference but it does not accept routes so I use routes.orNotFound.

Paul Snively
@paul-snively
What does it say without the .orNotFound?
I’m guessing you need -Ypartial-unification in scalacOptions.
Dario Abdulrehman
@dabd
@paul-snively I get expecting Kleisli[IO, NotInferred, Response[IO]] found HttpRoutes[IO]
I have -Ypartial-unification
Fabio Labella
@SystemFw
@dabd exactly, you want to do HttpRoutes => HttpRoutes, and instead of just applying the middleware, you are going orNotFound and then mapK. Let me try with the custom response
Paul Snively
@paul-snively
That’s a weird error, all right.