0
votes

I am re-learning Scala, and I wanted to do a system flow as follows

Routes(Akka-Http) which asks an Actor Model(Akka) which then asks the Database through a Slick Model.

Something like

Route

path("rooms"){
  get {
    val rooms = (actorRoom ? GetRooms).mapTo[Seq[Room]] //bad code
    complete(rooms) //bad code
  }
}

ActorRoom

def receive = {
  case GetRooms => sender() ! ModelRoom.getRooms()

Slick Model

val rooms = TableQuery[RoomTable]
def getRooms(): Future[Seq[Room]] = rooms.result

My problem is that i am not sure when to resolve the rooms.

Should I do it within the actor? (the route complete does not seem to wait)

Should I do it within the route? (how should i do it?)

Is this approach correct, or the actor is too much?

1

1 Answers

3
votes

Adding an Actor in the flow when your DB call itself is asynchronous can be dangerous since it can lead to un-predictable results.

But if you ignore all the unpredictability and still want to do it, you can make it work like this,

your route,

import akka.pattern.ask
import akka.actor.Status
import scala.util.{Success, Failure}

path("rooms"){
  get {
    val dbCallThroughActor = (actorRoom ? GetRooms).map({
      case Status.Success(seq) => seq
      case Status.Failure(ex) => throw ex
    })
    onComplete(dbCallThroughActor.mapTo[Seq[Room]]) {
      case Success(seq) => complete(seq)
      // or your can reject with your rejection handler
      case Failure(ex) => complete(ex)
    }
  }
}

your actor,

import context.dispatcher

def receive = {
  case GetRooms =>
    ModelRoom.getRooms().pipeTo(sender())
}

your slick model,

val rooms = TableQuery[RoomTable]
def getRooms()(implicit ec: ExecutionContext): Future[Seq[Room]] = database.run(rooms.result)