[2.4.0] Slick & ExecutionContexts

168 views
Skip to first unread message

Dominik Dorn

unread,
Jun 8, 2015, 6:02:06 PM6/8/15
to play-fr...@googlegroups.com

Hi!

I just integrated Slick 3 in my Play 2.4 project using the play-slick plugin ( "com.typesafe.play" %% "play-slick" % "1.0.0" ).

Reading through the docs, I didn't find any information on which ExecutionContext I'm supposed to import for

- Slick Code/Calls used in Controllers
- Slick Code/Calls used in Actors

The scala compiler wants me to import scala.concurrent.ExecutionContext.Implicits.global
while recently I learned I should import play.api.libs.concurrent.Execution.Implicits.defaultContext for asynchronous stuff in my controllers instead...

The slick documentation only states that Play / Akka may provide a better ExecutionContext ( "When using Slick as part of a larger application (e.g. with Play or Akka) the framework may provide a better alternative to this default ExecutionContext." http://slick.typesafe.com/doc/3.0.0/gettingstarted.html ) however, I can't find any information about which one I should use.

I have some DB-Access code directly in my controllers and some in some actors (I know, I should refactor it...). 

Please advice, on which ExecutionContexts I should be using and if necessary, how to configure them :) 

Thanks,
Dominik

Mirco Dotta

unread,
Jun 8, 2015, 6:36:39 PM6/8/15
to play-fr...@googlegroups.com
Hi Dominik,

As a general rule, in your Play code you should avoid using the Scala global execution context. Rather, use the Play default one, as hinted in https://www.playframework.com/documentation/2.4.x/ThreadPools#Using-the-default-thread-pool (the link also contains information for configuring it).

By the way, Slick creates and manages its own thread pool for executing all database actions. Therefore, the Play execution context is only needed when doing additional operation on the result of a db action.

Cheers,
Mirco
----------------
Mirco Dotta - @mircodotta

Typesafe – Build reactive apps!

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/398271a3-9396-46ea-bbed-38c84e6885fa%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

signature.asc

Dominik Dorn

unread,
Jun 9, 2015, 4:09:53 AM6/9/15
to play-framework
Thanks for your answer Mirco!

hmm, I think its very often the case that its required to do some stuff on the result of a db-query? 

e.g. right now my action looks like this 

def index = Action.async {
val query: DBIO[Seq[Details]] = sql"""SELECT
id, request_id, now,
remote_address, user_agent, status,
signature,
data, returncode, response, nanotime
FROM json_log ORDER BY id DESC LIMIT 60""".as[Details]

val data: Future[Map[String, Seq[Details]]] = dbConfig.db.run(query).map(a => a.seq.groupBy(b => b.now.getTime.toString.substring(0, 10) +"_"+ b.requestId))
data.map(a => Ok(views.html.sysadmin.browseCollectorLog.index(a))) }
just for mapping the query-future to the thing I need in my View I already need an ExecutionContext ... even when not using the transformation I'm doing, I think I would need the last map operation to render the view so I can fulfill the contract of Action.async ?
Maybe I understood something wrong?

What happens if I attach the map to the query itself, like
val data: Future[Map[String, Seq[Details]]] = dbConfig.db.run(query.map(a => a.seq.groupBy(b => b.now.getTime.toString.substring(0, 10) +"_"+ b.requestId)))
?
Will the transformation be done in the ExecutionContext of Slick or the one of Play? Does it actually matter? Maybe I'm too much concerned about a thing that's not worth thinking about?
Thanks, Dominik


For more options, visit https://groups.google.com/d/optout.



--
Dominik Dorn
http://dominikdorn.com
http://twitter.com/domdorn

Skripten, Mitschriften, Lernunterlagen, etc. findest Du auf http://www.studyguru.eu !

Julien Richard-Foy

unread,
Jun 10, 2015, 4:14:17 AM6/10/15
to play-fr...@googlegroups.com
Hi,

I think it is more a Slick question than a Play question. I will try to answer.


val data: Future[Map[String, Seq[Details]]] = dbConfig.db.run(query).map(a => a.seq.groupBy(b => b.now.getTime.toString.substring(0, 10) +"_"+ b.requestId))
data.map(a => Ok(views.html.sysadmin.browseCollectorLog.index(a))) }
just for mapping the query-future to the thing I need in my View I already need an ExecutionContext ... even when not using the transformation I'm doing, I think I would need the last map operation to render the view so I can fulfill the contract of Action.async ?
Maybe I understood something wrong?

What happens if I attach the map to the query itself, like
val data: Future[Map[String, Seq[Details]]] = dbConfig.db.run(query.map(a => a.seq.groupBy(b => b.now.getTime.toString.substring(0, 10) +"_"+ b.requestId)))
?
Will the transformation be done in the ExecutionContext of Slick or the one of Play? Does it actually matter? Maybe I'm too much concerned about a thing that's not worth thinking about?

To me, both are equivalent: in both cases, the function you pass to the map method is executed in a different execution context than the database connections thread pool. You can use the Play execution context for that, anyway Slick takes care of the parts of your computations that actually talk to the database and executes them in an execution context managed by Slick.

Mirco Dotta

unread,
Jun 10, 2015, 5:36:29 AM6/10/15
to play-fr...@googlegroups.com
> Thanks for your answer Mirco!
>
> hmm, I think its very often the case that its required to do some stuff on the result of a db-query?
>
> e.g. right now my action looks like this
>
> def index = Action.async {
> val query: DBIO[Seq[Details]] = sql"""SELECT
> id, request_id, now,
> remote_address, user_agent, status,
> signature, data, returncode, response, nanotime
> FROM json_log ORDER BY id DESC LIMIT 60""".as[Details]
>
> val data: Future[Map[String, Seq[Details]]] = dbConfig.db.run(query).map(a => a.seq.groupBy(b => b.now.getTime.toString.substring(0, 10) +"_"+ b.requestId))
> data.map(a => Ok(views.html.sysadmin.browseCollectorLog.index
> (a)))
> }
>
> just for mapping the query-future to the thing I need in my View I already need an ExecutionContext ... even when not using the transformation I'm doing, I think I would need the last map operation to render the view so I can fulfill the contract of Action.async ?

You are right - it was late when I answered and haven’t really thought it through :-)

> Maybe I understood something wrong?
>
>
> What happens if I attach the map to the query itself, like
>
> val data: Future[Map[String, Seq[Details]]] = dbConfig.db.run(query.map(a => a.seq.groupBy(b => b.now.getTime.toString.substring(0, 10) +"_"+ b.requestId)))
> ?
> Will the transformation be done in the ExecutionContext of Slick or the one of Play?

To know that, you should check the signature of the methods you are calling. For instance, the `query.map` expression in your code takes two arguments: a function, and an implicit ExecutionContext. Therefore, the function application will be executed on the ExecutionContext that you make available in the scope of that expression (entailing that it won’t be executed using the Slick managed thread pool, unless of course you explicitly import the Slick execution context in the current scope - don’t do that :-)). This makes sense as you want the Slick thread pool to be available to execute db actions.

> Does it actually matter? Maybe I'm too much concerned about a thing that's not worth thinking about?

I think you are asking really good questions, and I’d definitely say these are aspects worth thinking about.
> To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/CABHM76UynbOuaOcmgXCm48B7saS9ntWbmZHMn3-49Bjse144SQ%40mail.gmail.com.
signature.asc
Reply all
Reply to author
Forward
0 new messages