1

I'm trying to combine Playframework with Cats Effect 3 Tagless Final style.

I'm stuck on the transformation to the Future. Play's Action requires either just value or Future, which I want to reach, for async processing.

def method = authed { _ => 
  val program: EitherT[IO, Throwable, Int] = ???
  program
}

def authed[F[_]: Async](fa: Request => F[Result]): Action = {
 ???
}

In cats effect 2 it was possible via _.toIO.unsafeToFuture but now it's changed. According to the doc I must use Dispatcher. Found the initial idea on Github but a new signature is F[Future[A]]

def beforeF[F[_]: Effect, A](fa: F[A]): Future[A] = fa.ioIO.unsafeToFuture()
// Note: Using a `Dispatcher` resource is cheap - don't worry about it
def preferredAfterF[F[_]: Async, A](fa: F[A]): F[Future[A]] = Dispatcher[F].use(_.unsafeToFuture(fa))

Does anyone have success?

skilgal
  • 172
  • 1
  • 4
  • 14
  • The problem is that you are trying to create a `Dispatcher` for each request, which is wrong, you should create only one and pass it down to where you needed that way you will have just a `Future[A]`. Now, if you are able to use `IOApp` then you should be able to create the dispatcher there and combine it with all your other dependencies, if not then you would need to call `unsafeRunSync()` when you create the dispatcher. – Luis Miguel Mejía Suárez May 05 '22 at 13:19
  • @LuisMiguelMejíaSuárez form my curiosity, may be I am a foolish, I have a question, is not it a redundancy using cats effects with playframwork ? – John Oct 25 '22 at 10:11
  • @John it depends, in theory, no since **cats-effect** is mostly about how you build programs and **Play** is more about the HTTP framework. However, it is true that the way **Play** works make interoperating with `IO` kind of difficult. - So, in general, I don't think **Play** + **cats-effect** is a good design to start a new project _(although that is also in part because I don't think that using **Play** at all to be a good idea)_, but is combination is a common step in the process of migrating from one ecosystem to another; also, the mix is NOT great to learn **cats-effect**. – Luis Miguel Mejía Suárez Oct 25 '22 at 12:43
  • @LuisMiguelMejíaSuárez can you kindly clear this part ' I don't think that using Play at all to be a good idea' ? – John Oct 25 '22 at 15:42
  • @John is mostly a personal opinion, I really don't like the architectural decisions made by **Play**, like having the front-end and back-end integrated into the same service, dependency injection, the way it manages SQL queries, the way it manages the build; etc. – Luis Miguel Mejía Suárez Oct 25 '22 at 15:48
  • @LuisMiguelMejíaSuárez now I understand – John Oct 25 '22 at 15:52

1 Answers1

1

Contruct your routes so that they have access to a Disptacher object as a dependency, then the lifecycle will be appropriate

class MyRoute[F[_]: MonadThrow](disp: Dispatcher[F]) {
  def method = authed { _ => 
    val program: EitherT[IO, Throwable, Int] = ???
    disp.unsafeToFuture(program.value)
  }
}

(this might require some fiddling using allocated and the IORuntime's unsafeRunSync on a Dispatcher[IO] resource, depending on how your application is wired)

Daenyth
  • 35,856
  • 13
  • 85
  • 124