Scala + Play Framework + Slick + Akka - DB Access from Akka Actor - scala

At the receival of a TCP specific message, i need to query my DB. For that, i created an Actor that is called DBActor and it's loaded in Application.scala file
class Application #Inject() (system: ActorSystem) extends Controller {
val tcpServer = system.actorOf(Props[TCPServer], "tcpserver")
val dbActor = system.actorOf(Props[DBActor], "dbActor")
}
Tcp server is the actor that received the message and need to push it on DB Actor with that
val handler = context.actorSelection("/dbActor")
DB actor is so initialized in this way, according to Play Framework specifications
object DBActor {
def props() =
Props(classOf[DBActor])
}
class DBActor #Inject() (protected val dbConfigProvider:
DatabaseConfigProvider) extends Actor
with HasDatabaseConfigProvider[JdbcProfile]
with ActorLogging
with TableComponent {
import akka.io.Tcp._
import driver.api._
val table = TableQuery[Table]
def receive: Receive = {
case GetConfig(id) => {
sender ! Await.result(db.run(table.filter(_.id=== id).result.headOption),
Duration.Inf)
.map { x => x.config }
}
}
}
At the moment, actor is not constructed due to the error
Error injecting constructor, java.lang.IllegalArgumentException:
no matching constructor found on class tcp.DBActor for arguments []
at controllers.Application.<init>(Application.scala:17)
at controllers.Application.class(Application.scala:17)
So i need a way to inject the db configuration in the DBactor for querying the database or an alternative. I evaluated before that to inject a DAO or transforming the DAO I needed into an actor, both failed.
Question at this point is, does it make any sense giving an actor the access to the db or, at least, a controller? If can't be done, what are the alternatives?

What you need is an injected actor. The full description can be found here in the play documentation (https://www.playframework.com/documentation/2.5.x/ScalaAkka#Dependency-injecting-actors), but here's the gist of it:
You define the actor binding like so:
bindActor[DBActor]("db-actor")
And inject the actor in the controller like so:
class Application #Inject() (#Named("db-actor") dbActor: ActorRef) extends Controller {
On a different note, you should avoid Await.result whenever possible. In your scenario, this could probably easily be replaced with:
val senderRef = sender()
db.run(table.filter(_.id=== id).result.headOption)
.map(res => senderRef ! res.config)
Note that the sender ref is stored before, because it is no longer valid inside the map (see scaladoc of the sender() method).

Related

Akka HTTP: How to split routes with actors

I have an old Scala/Akka Http project that I'm trying to simplify and refactor. I was wondering if there's a better way to organize routes and perhaps split them across actors. Here's what I have at the moment (far from ideal):
```
object MyAPI {
def props(): Props = Props(new MyAPI())
val routes = pathPrefix("api") {
pathPrefix("1") {
SomeActor.route //More routes can be appended here using ~
}
}
}
final class MyAPI extends Actor with ActorLogging {
implicit lazy val materializer = ActorMaterializer()
implicit lazy val executionContext = context.dispatcher
Http(context.system)
.bindAndHandleAsync(Route.asyncHandler(MyAPI.routes), MyHttpServer.httpServerHostName, MyHttpServer.httpServerPort)
.pipeTo(self)
override def receive: Receive = {
case serverBinding: ServerBinding =>
log.info(s"Server started on ${serverBinding.localAddress}")
context.become(Actor.emptyBehavior)
case Status.Failure(t) =>
log.error(t, "Error binding to network interface")
context.stop(self)
}
}
```
```
object SomeActor {
def props(): Props = Props[SomeActor]
val route = get {
pathPrefix("actor") {
pathEnd {
complete("Completed") //Is there a clean way 'ask' the actor below?
}
}
}
}
class SomeActor extends Actor with ActorLogging {
implicit lazy val executionContext = context.dispatcher;
override def receive: Receive = {
//receive and process messages here
}
```
So, my question is - is there a clean way to structure and refactor routes instead of lumping them together in one large route definition? I could perhaps create a hierarchy of actors (routers) and the main route definition just delegates it to the routers and we incrementally add more details as we go deeper in the actor hierarchy. But is there a generally accepted patter or two to organize routes?
I would like to suggest you on the basis of the functionality you can have as many actors you you want, but create one supervisor actors which will keep watch on each child actor. And all the supervision strategies should be written into the supervisor itself, and all the msg you gonna sent to the actors should be forwarded by the supervisor.
As soon as you get the data from the end point, may be get or post method take the data into someRequest case class. Then sent it to some handleReq() method. And then do your processing make traits on functionality basis.
You can structure project something like this.
src/
actor//all the actors will be in this package
model// all the case classes and constants
repo// all the db related function you can do here
service// all your routes and endPoint functions
Now you can have package util where all the utilities trait you can put which will be used by any of the actor, or service may be you have lots of validations you can have a package named validator.
The structure is depends on your business. I think it would help.

Get context from Main Actor in Akka

I'm attempting to shoot fire off a POST request like the one in the Akka docs showed here. http://doc.akka.io/docs/akka-http/current/scala/http/client-side/request-level.html#request-level-api
However, I'm trying to do it as inside of another defined class. If I try to add in anything that requires the Actor context like val http = HTTP(context.system) I get an error. How can I pass in the context into the class I'm trying to make the POST request from?
trait CustomerProfilesComponent {
def customerProfileManager: CustomerService.Async
}
object DefaultCustomerProfiles {
private case class ProfileUpdateData(path: Seq[String], data: JsObject, metadata: JsObject)
}
trait DefaultCustomerProfiles extends CustomerProfilesComponent {
self: DatabaseComponent with SourceVersionComponent with ExecutionContextComponent =>
import DefaultCustomerProfiles._
lazy val customerProfileManager = new CustomerService.Async {
import db.api._
import AvroConverter._
override def getVersion : Future[AvroVersion] = {
Future.successful(toAvro(sourceVersion))
}
}
What you need is actually an actor system. Posting from the akka-http docs:
The request-level API is implemented on top of a connection pool that is shared inside the ActorSystem.
There are two usage scenarios for the request API:
use it within an actor - when you can get the actor system via the actor context (like you have tried, but since you are not inside an actor, you don't have an actor context available)
use it outside an actor (your case) - when you can get the actor system by providing it as an dependency (either via class/method params or implicit params)
I hope this is helpful.

Play! scala and Akka: how to test if an actor A sent a message to an actor B?

I want to test that an actor A send a message to an actor B after have received a message.
I'm using Play! 2.5 and I use the factories since I need to inject some of my classes and things like wSClient inside the actors.
The Actor A looks like:
object ActorA {
trait Factory {
def apply(ec: ExecutionContext, actorBRef: ActorRef): Actor
}
}
class ActorA #Inject()(implicit val ec: ExecutionContext,
#Named("actor-b") actorBRef: ActorRef)
extends Actor with ActorLogging with InjectedActorSupport {
override def receive: Receive = {
case i: Long =>
log info s"received $i"
actorBRef ! (i+1)
}
And the actor B is even more simple:
object ActorB {
trait Factory {
def apply(): Actor
}
}
class ActorB extends Actor with ActorLogging {
override def receive: Receive = {
case _ =>
log error "B received an unhandled message"
}
}
But my test doesn't pass, it is said that the expected message doesn't arrive, I get a Timeout in the test (but it is well logged by the actor B) so the problem comes from the test (and probably the Probe).
Here is the test:
val actorBProbe = TestProbe()
lazy val appBuilder = new GuiceApplicationBuilder().in(Mode.Test)
lazy val injector = appBuilder.injector()
lazy val factory = injector.instanceOf[ActorA.Factory]
lazy val ec = scala.concurrent.ExecutionContext.Implicits.global
lazy val factoryProps = Props(factory(ec, actorBProbe.ref))
val ActorARef = TestActorRef[ActorA](factoryProps)
"Actor B" must {
"received a message from actor A" in {
ActorARef ! 5L
actorBProbe.expectMsg(6L)
}
}
I also created a minimum Play! application with the code above available here.
In your test, actorBProbe is not the ActorB ref passed to ActorA constructor (of ref ActorARef). What really happens is that Guice creates a different ActorB (named actor-b), and passes its ref to ActorA (of ref ActorARef) constructor.
The test ends up with ActorB actor-b receiving 6L (as evident in log). While actorBProbe receives nothing.
The confusion really comes from mixing Guice lifecyle with Actors. In my experience, it creates more pains than I can bear.
To prove, simply print hash code of ActorRef's, you'll see they are different. Illustrated as followings:
val actorBProbe = TestProbe()
println("actorBProbe with ref hash: " + actorBProbe.ref.hashCode())
And,
class ActorA ... {
override def preStart =
log error "preStart actorBRef: " + actorBRef.hashCode()
// ...
}
In fact, even ec inside ActorA is not the same ec in the test code.
The following is a way to "force" the test to pass and at the same time prove that actorBProbe wasn't really being used by ActorB.
In stead of relying on Guice to "wire in" ActorB, we tell Guice to leave it alone by replacing #Named("actor-b") with #Assisted, like this,
import ...
import com.google.inject.assistedinject.Assisted
class ActorA #Inject()(...
/*#Named("actor-b")*/ #Assisted actorBRef: ActorRef)
...
Re-run the test, it'll pass. But this is probably not what you wanted to begin with.

Scala and Akka - Testing actors as a system with Akka Testkit

In my Scala application say I have Actor A and Actor B. I want to devise a test case in ScalaTest that would allow me to send a message to Actor A and see what message it sends to Actor B in order to see if A is properly processing it's data and sending the right message to B. How would one test this? It took me a long time to get this cooked up on my own...but it does seem to mostly work.
class A extends Actor { ... }
class B extends Actor { ... }
class C(p: TestProbe) extends B {
override def receive = {
LoggingReceive {
case x =>
println(x.toString)
p.ref ! x
}
}
}
case class MsgToB(...)
// Spec class which extends TestKit
"A" should {
"send the right message to B" {
val p = TestProbe()
val a = TestActorRef[A]
val c = TestActorRef(Props(new C(p)))
// Assume A has a reference to C. Not shown here.
a ! msg
// Assert messages
p.expectMsgType[MsgToB]
}
}
Is this the best means of doing this? Is there a better practice?
To me it sounds like what you want is to test the behaviour of actor A in isolation. In order to do this, you need to be able to control how actor A gets its reference to actor B. For example, you could provide the reference in the actor's constructor:
import akka.actor.{Actor, ActorRef, Props}
class A(refToB: ActorRef) extends Actor { ... }
object A {
def props(refToB: ActorRef): Props = Props(new A(refToB))
}
There are alternative ways you can pass the reference to actor B to actor A, but using the constructor is arguably the easiest choice. In the example above, we also provide a method for creating the correct Props for the actor.
Now that you can control the reference to actor B, you can replace the actor reference with test probe in tests.
import akka.testkit.TestProbe
// Initialise a test probe
val probe = TestProbe()
// Actor A with reference to actor B replaced with the test probe
val a = system.actorOf(A.props(probe.ref))
// Send a message to actor A
a ! someMessage
// Verify that the probe received a correct response from actor A
p.expectMsgType[MsgToB]
Notice that I created the actor using the actor system from the TestKit instead of using the TestActorRef. This means that the actor message processing will be asynchronous instead of synchronous. Personally, I've found the asynchronous testing style to be a better fit because it better represents how the actor is run in a production system. Asynchronous testing is also recommended in the official documentation.

How to test controllers that has akka system injected for Play framework?

Below is my controller:
package controllers
import java.util.TimeZone
import akka.actor.{ActorNotFound, ActorSystem}
import akka.util.Timeout
import com.google.inject.Inject
import com.typesafe.akka.extension.quartz.QuartzSchedulerExtension
import play.api.Logger
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import play.api.libs.json.{JsValue, JsError, JsSuccess}
import play.api.mvc._
import scala.concurrent.Future
import scala.concurrent.duration._
class ScheduleController #Inject()(system: ActorSystem) extends Controller {
val scheduler = QuartzSchedulerExtension.get(system)
implicit val timeout = new Timeout(5.seconds)
def index = Action.async {
Future.successful(Ok("hi"))
}
def run = Action.async { request =>
// find actor and "start" it by sending message to it, return Ok() if found
// if actor is not found, return BadRequest()
// if error return InternalServerError()
}
}
I've been looking for tutorials but most are outdated since they deal with Play 2.3.
I solved a very similar problem with Play2 controllers and actors except in my case I'm not injecting an ActorSystem into my controller. Rather, I use Play's default actor system and create actors from my global settings object when my application starts. For a given actor I provide a selection method in its companion object. For example:
class MyActor extends Actor {
def receive = {
case Request => sender ! Response
}
}
object MyActor {
val path = // assuming fixed actor path
val sys = // reference to play actor system
def select: ActorSelection = sys.actorSelection(path)
// my actor messages
case object Request
case object Response
}
The way I have this actor setup I plan on asking it from inside my controller method using a Request and expect to process a Response object back from it. The controller is a non-actor sender in this scenario. By calling ask on the actor selection, I close over the future and map the result to a partial function that matches the expected response. Here's what my controller looks like:
class MyController extends Controller {
implicit val timeout = // set your timeout duration
def index = Action.async {
MyActor.select ? Request map {
case Response => Ok("success")
}
}
}
Testing this controller endpoint is VERY challenging because your actor might not be in a ready state to start handling messages. I spent about two days trying to figure out how to properly block on the my actor's lifecycle state using the actor selection I've exposed through its companion object. What I ended up doing inside my test class that worked for me was to create a method that takes in a function parameter and loops over my actor state until I can resolve its ActorRef. I'm a fan of ScalaTest so this is what my unit tests amounted to:
class MySpec extends FlatSpec with Matchers with BeforeAndAfterAll {
implicit val fakeApp: FakeApplication = new FakeApplication()
override def beforeAll() = Play.start(fakeApp)
override def afterAll() = Play.stop(fakeApp)
def awaitableActorTest(assertions: => Any): Unit = {
val timeout = 1.second
var isActorReady = false
while(!isActorReady) {
val futureRef = Await.ready(MyActor.select.resolveOne(timeout), timeout)
futureRef.value.get match {
case Success(_) =>
assertions
isActorReady = true
case Failure(_) =>
Thread.sleep(2000)
}
}
}
it should "process actor request and response via controller endpoint" in {
awaitableActorTest {
val result = route(routes.MyController.index).get
status(result) shouldBe OK
contentAsString(result) shouldBe "success"
}
}
}
What I get out of this awaitableActorTest pattern is a really clean way of reliably hitting my controller endpoint only when my actor is alive and available to process messages. If it's not, my ActorRef using its selection companion won't resolve in the future with success -- instead it completes with failure. When it fails I sleep a few seconds and repeat the loop. I break the loop when I its selection successfully resolved an ActorRef.
I'm unfamiliar with the QuartzSchedulerExtension to which you refer in your code snippet, but I hope my example is useful.