问题
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!
回答1:
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")
来源:https://stackoverflow.com/questions/19780545/play-slick-with-securesocial-running-db-io-in-a-separate-thread-pool