How to reference to the standard ActorSystem of play framework 2? - scala

I wish to use the scheduler of akka, the examples are saying:
system.scheduler.scheduleOnce()
but there is no real information where the "system" should come from. The documentation is a little bit superficial and there was a lot of change (akka moved out of core scala).
If I write
val system = akka.actor.ActorSystem("system")
I will have a ActorSystem, but it will be a new independent ActorSystem with around 8 new threads. I think, that this is an overkill for a small scheduler and not really recommended.
How can I just re-use the existing system of play framework 2 ?
Thanks

To get hands on the default actor system defined by Play you have to import the play.api.libs.concurrent.Akka helper.
Akka.system will be a reference to the default actor system, and then you can do everything with it as you would do with an actor system created by yourself:
import play.api.libs.concurrent.Akka
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")
Akka.system.scheduler.scheduleOnce(...)
update:
The above static methods became deprecated in Play 2.5 and was removed in 2.6, so now you have to use dependency injection.
In Scala:
class MyComponent #Inject() (system: ActorSystem) {
}
In Java:
public class MyComponent {
private final ActorSystem system;
#Inject
public MyComponent(ActorSystem system) {
this.system = system;
}
}

When you use play.api.libs.concurrent.Akka you are using the actor system created by play. In fact that is the way encouraged.
You can read that in the documentation.

Related

WS in Play become incredible complex for 2.6.X

For Play 2.3.X the WS module is very easy to be used:
WS.url(s"http://$webEndpoint/hand/$handnumber").get()
For the such simple and strightforward usage.
While in Play 2.6.x according to the link :
https://www.playframework.com/documentation/2.6.x/JavaWS
You need to create a http client firstly.
WSClient customWSClient = play.libs.ws.ahc.AhcWSClient.create(
play.libs.ws.ahc.AhcWSClientConfigFactory.forConfig(
configuration.underlying(),
environment.classLoader()),
null, // no HTTP caching
materializer);
And what's more, you also need a materializer and an akka system to support the materializer.
String name = "wsclient";
ActorSystem system = ActorSystem.create(name);
ActorMaterializerSettings settings = ActorMaterializerSettings.create(system);
ActorMaterializer materializer = ActorMaterializer.create(settings, system, name);
// Set up AsyncHttpClient directly from config
AsyncHttpClientConfig asyncHttpClientConfig = new DefaultAsyncHttpClientConfig.Builder()
.setMaxRequestRetry(0)
.setShutdownQuietPeriod(0)
.setShutdownTimeout(0).build();
AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(asyncHttpClientConfig);
// Set up WSClient instance directly from asynchttpclient.
WSClient client = new AhcWSClient(
asyncHttpClient,
materializer
);
I knew it will add more features to the WS client, but when I just want a simple http client, the usage become unaccept complex, it's so wired.
The page you link to says:
We recommend that you get your WSClient instances using dependency injection as described above. WSClient instances created through dependency injection are simpler to use because they are automatically created when the application starts and cleaned up when the application stops.
It shouldn't then surprise you that manually creating instance of WSClient is tedious.
And the same page describes how to use an injected version of WSClient:
import javax.inject.Inject;
import play.mvc.*;
import play.libs.ws.*;
import java.util.concurrent.CompletionStage;
public class MyClient implements WSBodyReadables, WSBodyWritables {
private final WSClient ws;
#Inject
public MyClient(WSClient ws) {
this.ws = ws;
}
// ...
}
This is as simple as it's used to be in the previous versions. Actually, in previous Play versions you also could have created the custom instance of WSClient, and that used to have comparable complexity (modulo Akka stuff).
Finally I use ScalaJ-http, https://github.com/scalaj/scalaj-http
Which is very easy to use:
import scalaj.http._
...
response= Http("http://localhost:5000/health").asString
Which is simple as WS in play 2.3.6
For Play 2.6.x the framework may not create the default ws for you and see the example of https://github.com/playframework/play-scala-tls-example/blob/2.6.x/app/Main.scala
For people using Scala Play with fully DI support one solution to create WSClient instance is Play.current.injector.instanceOf[WSClient]. That also useful when updating to Scala Play 2.6 with small changes without adding DI support to all.

How do I create thread pools in Play 2.5.x?

I am currently on Play 2.4.2 and have successfully created thread pools using the following below:
package threads
import scala.concurrent.ExecutionContext
import play.api.libs.concurrent.Akka
import play.api.Play.current
object Contexts {
implicit val db: ExecutionContext = Akka.system.dispatchers.lookup("contexts.db-context")
implicit val pdf: ExecutionContext = Akka.system.dispatchers.lookup("contexts.pdf-context")
implicit val email: ExecutionContext = Akka.system.dispatchers.lookup("contexts.email-context")
}
and then in the code with...
Future{....}(threads.Contexts.db)
We are ready to upgrade to Play 2.5 and having trouble understanding the documentation. The documentation for 2.4.2 uses Akka.system.dispatchers.lookup, which we use without issue. The documentation for 2.5.x uses app.actorSystem.dispatchers.lookup. As far as I know, I have to inject the app into a Class, not an Object. Yet the documentation clearly uses an Object for the example!
Has anyone successfully created thread pools in Play 2.5.x that can help out? Is it as simple as changing Contexts to a class, then injecting it wherever I would like to use this threading? Seems odd since to use the default ExecutionContext I just have to make an implicit import.
Also, we are using Play scala.
If you simply change your Contexts to a class, then you will have to deal with how to get an instance of that class.
In my opinion, if you have a number of thread pools that you want to make use of, named bindings are the way to go. In the below example, I will show you how you could accomplish this with guice.
Note that guice injects depedencies at runtime, but it is also possible to inject dependencies at compile time.
I'm going to show it with the db context as an example. First, this is how you will be using it:
class MyService #Inject() (#Named("db") dbCtx: ExecutionContext) {
// make db access here
}
And here's how you could define the binding:
bind[ExecutionContext].qualifiedWith("db").toProvider[DbExecutionContextProvider]
And somewhere define the provider:
class DbExecutionContextProvider #Inject() (actorSystem: ActorSystem) extends Provider[ExecutionContext] {
override def get(): ExecutionContext = actorSystem.dispatchers.lookup("contexts.db-context")
}
You will have to do this for each of your contexts. I understand this may be a little cumbersome and there may actually be more elegant ways to define the bindings in guice.
Note that I have not tried this out. One issue you might stumble upon could be that you'll end up with conflicts, because play already defines a binding for the ExecutionContext in their BuiltinModule. You may need to override the binding to work around that.

Alternative to using Akka.system inside an object

I am learning the Play Framework together with Scala, and I looked at the reactive-stocks tutorial that comes with activator for learning more about the framework.
In the learning project that I am creating (a simple chat) I want to have something similar to this snippet taken out from the tutorial:
object StocksActor {
lazy val stocksActor: ActorRef = Akka.system.actorOf(Props(classOf[StocksActor]))
}
That is, an actor that will only be instanciated one time on the application. But I found out that Akka.system is deprecated, so I should use dependency injection to get the ActorSystem. How would I do dependency injection in an Object?
object ChatRoomsActor #Inject() (actorSystem: ActorSystem) {
lazy val ref: ActorRef = actorSystem.actorOf(Props(classOf[ChatRoomsActor]))
}
I tried this code, but it doesn't work.

Play 2.4: Schedule a recurring task at app startup with dependency injection

I need to schedule a recurring task on the application start, the task itself is very simple just send to the application a fire-and-forget HTTP call. I'm not a play expert, buy i would assume that s straightforward solution would be something like using play.api.libs.concurrent.Akka.system.schedule in Global.onStart. Since Play 2.4, Global configuration is somewhat deprecated in favor of new Guice DI. Hacking the advice from the DI documentation i couldn't come up with a nice solution for this issue. The best i managed to get is writing a wrapper on top of GuiceApplicationLoader calling a custom implementation of BuiltInComponentsFromContext, but in this case i can't use injection to get WSClient. What's the best way to rewrite something like this with Play 2.4:
object Global extends GlobalSettings {
override def onStart(app: Application) = {
Akka.system.schedule(2.hours, 2.hours, theTask)
}
}
Update: this is now better documented for Play 2.6: https://www.playframework.com/documentation/2.6.x/ScheduledTasks
You can solve this by creating a module like this (attention to code comments):
package tasks
import javax.inject.{Singleton, Inject}
import akka.actor.ActorSystem
import com.google.inject.AbstractModule
import play.api.inject.ApplicationLifecycle
// Using the default ExecutionContext, but you can configure
// your own as described here:
// https://www.playframework.com/documentation/2.4.x/ThreadPools
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scala.concurrent.Future
import scala.concurrent.duration._
class MyRecurrentTaskModule extends AbstractModule {
override def configure() = {
// binding the RecurrentTask as a eager singleton will force
// its initialization even if RecurrentTask is not injected in
// any other object. In other words, it will starts with when
// your application starts.
bind(classOf[RecurrentTask]).asEagerSingleton()
}
}
#Singleton
class RecurrentTask #Inject() (actorSystem: ActorSystem, lifecycle: ApplicationLifecycle) {
// Just scheduling your task using the injected ActorSystem
actorSystem.scheduler.schedule(1.second, 1.second) {
println("I'm running...")
}
// This is necessary to avoid thread leaks, specially if you are
// using a custom ExecutionContext
lifecycle.addStopHook{ () =>
Future.successful(actorSystem.shutdown())
}
}
After that, you must enable this module adding the following line in your conf/application.conf file:
play.modules.enabled += "tasks.MyRecurrentTaskModule"
Then, just start you application, fire a request to it and see the scheduled task will run every each second.
References:
Understanding Play thread pools
Play Runtime Dependency Injection for Scala
Integrating with Akka
Related questions:
How to correctly schedule task in Play Framework 2.4.2 scala?
Was asynchronous jobs removed from the Play framework? What is a better alternative?

How to gain access to the akka system created via guice?

So I'm following the template here:
https://github.com/rocketraman/activator-akka-scala-guice#master
I've ported this code over to a version 2.4 Play app.
Now I am able to create the actor system and create the actors inside the Global class and send the initial messages to the actors. I've also set up routes to try to talk to certain actors and get status but I am unable to since I cannot access that original actor system.
How can I accomplish this? I think in the older Play versions, we have getControllerInstance; which is used in the following:
/**
* Controllers must be resolved through the application context. There is a special method of GlobalSettings
* that we can override to resolve a given controller. This resolution is required by the Play router.
*/
override def getControllerInstance[A](controllerClass: Class[A]): A = injector.getInstance(controllerClass)
From that, we can inject certain dependencies in the controller. Now that this is removed, we can no longer do that. Is there a way around this?
It's pretty clear how to inject Akka system in to the controller
import play.api.mvc._
import akka.actor._
import javax.inject._
import actors.HelloActor
#Singleton
class Application #Inject() (system: ActorSystem) extends Controller {
val helloActor = system.actorOf(HelloActor.props, "hello-actor")
//...
}
take in to attention #Singleton here is only to store reference to the actor - not the ActorSystem, it's handled by the Play in backend
A Play application defines a special actor system to be used by the
application. This actor system follows the application life-cycle and
restarts automatically when the application restarts.