Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running queries in parallel in Doobie

Is it possible to run multiple queries in parallel, using Doobie?

I have the following (pseudo)queries:

def prepareForQuery(input: String): ConnectionIO[Unit] = ???
val gettAllResults: ConnectionIO[List[(String, BigDecimal)]] = ???
def program(input : String) : ConnectionIO[List[(String, BigDecimal)]] = for{
    _ <- prepareForQuery(input)
    r <- gettAllResults
  } yield r

What I tried is the following:

import doobie._
import doobie.implicits._
import cats.implicits._
val xa = Transactor.fromDataSource[IO](myDataSource)
val result = (program(i1),program(i2)).parMapN{case (a,b) => a ++ b}
val rs = result.transact(xa).unsafeRunSync

However, no NonEmptyParallel instance is found for ConnectionIO.

Error:(107, 54) could not find implicit value for parameter p: cats.NonEmptyParallel[doobie.ConnectionIO,F] val result = (program(i1),program(i2)).parMapN{case (a ,b) => a ++ b}

Am I missing something obvious or trying something that cannot be done? Thanks

like image 941
mdm Avatar asked Jun 13 '18 09:06

mdm


1 Answers

You cannot run queries in the ConnectionIO monad in parallel. But as soon as you turn them into your actual runtime monad (as long as it has a Parallel instance), you can.

For example, with the cats-effect IO runtime monad:

def prepareForQuery(input: String): ConnectionIO[Unit] = ???
val gettAllResults: ConnectionIO[List[(String, BigDecimal)]] = ???
def program(input : String) : ConnectionIO[List[(String, BigDecimal)]] = for{
    _ <- prepareForQuery(input)
    r <- gettAllResults
  } yield r

Turn your ConnectionIO into an IO

val program1IO: IO[List[(String, BigDecimal)]]] = program(i1).transact(xa)
val program2IO: IO[List[(String, BigDecimal)]]] = program(i2).transact(xa)

You now have a monad which can do things in parallel.

val result: IO[List[(String, BigDecimal)]]] = 
    (program1IO, program2IO).parMapN{case (a,b) => a ++ b}

To understand why ConnectionIO doesn't allow you to do things in parallel, I'll just quote tpolecat:

You can't run ConnectionIO in parallel. It's a language describing the use of a connection which is a linear sequence of operations.

Using parMapN in IO, yes, you can run two things at the same time because they're running on different connections.

There is no parMapN with ConnectionIO because it does not (and cannot) have a Parallel instance.

like image 146
soote Avatar answered Oct 23 '22 22:10

soote