Можно ли разделить чистое состояние FP между несколькими HTTP-запросами на сервере http4s?

Я пытаюсь разделить состояние между несколькими HTTP-запросами на http4s сервере.

Вот что я пробовал:

for {
     state  <- Ref[F].of(0)
 
    _ <- BlazeServerBuilder[F]
         .bindHttp(port, host)
         .withHttpApp( ... httpApp that has link to "state" ... )
         .serve.compile.lastOrError

} yield  () 

Состояние остается прежним после того, как я изменю его внутри http-запроса.

Можно ли разделить состояние в чистом стиле FP, используя Ref или что-то из Fs2?

ОБНОВЛЕНИЕ: проблема была внутри моего приложения. не связано с тем, как я сдаю Ref. моя вина.


person Bogdan Vakulenko    schedule 05.07.2020    source источник


Ответы (1)


Вы можете легко изменить состояние внутри HTTP-запроса. Побочные эффекты — это весь смысл монады IO, а изменяемое состояние — это то, для чего предназначено Ref. Вот пример маршрута, который будет подсчитывать количество вызовов:

  def countRoutes[F[_]: Defer: Monad](ref: Ref[F, Int]): HttpRoutes[F] = {
    val dsl = new Http4sDsl[F]{}
    import dsl._
    HttpRoutes.of[F] {
      case GET -> Root / "count" =>
        for {
          current  <- ref.updateAndGet(_ + 1)
          resp <- Ok(current.toString)
        } yield resp
    }
  }

Однако ваш код инициализации выглядит странно. Это должно быть что-то вроде этого:

for {
    state  <- Ref[IO].of(0)
    exitCode <- BlazeServerBuilder[F]
           .bindHttp(port, host)
           .withHttpApp( ... httpApp that has link to "state" ... )
           .serve.compile.lastOrError
} yield exitCode
person Matthias Berndt    schedule 05.07.2020
comment
Я столкнулся с почти такой же проблемой. Можно ли использовать Ref в случае, если каждый запрос выделяет несколько Resource, которые затем объединяются вместе для освобождения? Я имею в виду что-то вроде Ref[F, Resource[F, Unit]] - person Some Name; 05.07.2020