8

I have a Play 2.2.1 app that uses play-slick 0.5.0.8 to persist data to a Postgresql backend and SecureSocial 2.1.2 to handle user authorisation.

Since play-slick transactions are blocking, I have created a separate slick-context execution context in my /conf/application.conf file, as per the instructions found in the plugin's Wiki:

play {
  akka {
    actor {
      slick-context = {
        fork-join-executor {
          parallelism-min = 300
          parallelism-max = 300
        }
      }
    }
  }
}

This allows me to create a controller Action that runs in a separate execution context and does not block threads in the default thread pool. Eg. /app/controllers/Application.scala:

Example One - Using play-slick's DBAction:

import play.api.db.slick._
object Application extends Controller{ 

  // this controller Action won't block threads in the default pool since DBAction uses my separate slick-context execution context
  def recipes = DBAction { implicit rs =>
    val recipes  = Query(Recipes).list
    Ok(recipes.mkString)
  }

}

For certain controller actions I want to be able to utilise SecureSocial's Actions (SecuredAction, UserAwareAction etc) in conjunction with play-slick's DBAction. What is the best way to combine the two?

I realise I can do something like the below, but my understanding is that the DB call won't use my separate slick-context and will therefore block the default thread pool:

Example Two - Using SecureSocial's Action:

import play.api.db.slick._
import securesocial.core._
object Application extends Controller{ 

  // changing from a DBAction to a SecuredAction so that I can use SS's goodies
  def recipes = SecuredAction { implicit request =>
    val recipes  =  DB.withSession { implicit session:Session => Query(Recipes).list } // i'm guessing this WILL BLOCK the default thread pool since it isn't using my separate slick-context execution context??
    Ok(recipes.mkString)
  }

}

Am I correct in assuming that Example Two will use/block the default thread pool instead of my separate slick-context thread pool? If so, is there a way to change this?

I could obviously get around this by bumping up Play's default thread pool (default-dispatcher), but ideally I want to keep the default thread pool quite lean, and run all blocking DB calls in a separate pool.

Assistance appreciated!

dbau
  • 16,009
  • 2
  • 21
  • 31
  • Did you find a good way to do this, to use DBAction with SecuredAction? a better way? – Phil May 06 '15 at 06:50

1 Answers1

7

To answer your question,

Am I correct in assuming that Example Two will use/block the default thread pool instead of my separate slick-context thread pool? If so,

Yes, that would use up/block the default pool.

If you want to use the separate slick-context thread pool, then you could try something like this?

  import scala.concurrent.Future

  // Note the use of '.async' |
  //                          V
  def recipes = SecuredAction.async { implicit request =>
    Future { // your code that may block
      val recipes  =  DB.withSession { implicit s:Session => 
        Query(Recipes).list 
      } 
      Ok(recipes.mkString)
    } 
  }

Future expects an ExecutionContext (an implicit will do); all you need to to pass in the one that play-slick uses (implicitly):

import play.api._
implicit val slickExecutionContext = 
  Akka.system.dispatchers.lookup("play.akka.actor.slick-context")
Faiz
  • 16,025
  • 5
  • 48
  • 37
  • Faiz, is there a way to debug what is running in the default context versus another context? i.e. can you add logging somehow or is this something you just have to get your head around and understand. – Blankman May 02 '14 at 14:48