Ich habe den folgenden Code, der eine Antwort an den Absender-Akteur zurücksendet (der antwortende Akteur lädt mit Slick eine Liste aus einer Tabelle):
class ManageUsersData extends Actor {
def receive = {
case _ => {
sender ! loadUsers
}
}
def loadUsers = {
var list = new ListBuffer[String]()
val db = Database.forConfig("dbconfig")
try {
val users: TableQuery[Users] = TableQuery[Users]
val future = db.run(users.result)
future onComplete {
case Success(u) => u.foreach {
user => {
list += user.firstName
}
list
}
case Failure(t) => println("An error has occured: " + t.getMessage)
}
} finally db.close
list
}
}
Das Problem hierbei ist, dass loadUsers
zurückkehrt, bevor auf den Abschluss der Zukunft gewartet wird. Wie kann das angegangen werden?
3 Antworten
Sie sollten das Rohrmuster verwenden:
import akka.pattern.pipe
// ...
def receive = {
val originalSender = sender
loadUsers pipeTo originalSender
}
Die konzeptionelle Lösung wird bereits von Jean Logeart erwähnt. In Bezug auf loadUsers denke ich, dass dies eine kürzere Version ist?
def loadUsers = {
val db = Database.forConfig("dbconfig")
try {
val users: TableQuery[Users] = TableQuery[Users]
db.run(users.result).map(_.firstName)
} catch {
case e: Exception => println("An error has occured: " + e.getMessage)
} finally db.close
}
Aus meiner Sicht wäre es am einfachsten, das future
einfach an das sender
zurückzusenden, anstatt an das asynchron gefüllte list
.
Wie in
def loadUsers = {
val db = Database.forConfig("dbconfig")
try {
val users: TableQuery[Users] = TableQuery[Users]
val future = db.run(users.result)
future.map { //the future
_.map { //the returning Seq
_.firstName
}
}
} finally db.close
}
Jetzt hat der Anrufer die Last, die Zukunft oder den Fehler zu bewältigen.
Dies hat auch den Nachteil, dass, wenn sender
die Operation ask
/ ?
verwendet, das asynchrone Ergebnis ein Future
ist, das ein weiteres Future
umschließt.
Sie können dieses Problem mithilfe der Methode pipeTo
beheben, die eine zukünftige Nachricht an den Anrufer sendet, ohne sich darum kümmern zu müssen, sie zu entpacken.
Der Nachteil von piping ist, dass das sender
eine Möglichkeit haben sollte, zu identifizieren, welche Antwort zu welcher Anforderung gehört. Eine mögliche Lösung besteht darin, eine Anforderungskennung zu senden, die mit der Antwort zurückgesendet wird, damit der anfordernde Akteur die beiden leicht verknüpfen kann.
Randnotiz
Warum sollten Sie im zukünftigen Ergebnis das Attribut firstName
zuordnen, anstatt eine Projektion in der Slick-Abfrage zu verwenden? Ich nehme an, es ist, um das Beispiel einfach zu halten.
Neue Fragen
scala
Scala ist eine universelle Programmiersprache, die hauptsächlich auf die Java Virtual Machine abzielt. Es wurde entwickelt, um gängige Programmiermuster auf präzise, elegante und typsichere Weise auszudrücken. Es vereint sowohl imperative als auch funktionale Programmierstile. Seine Hauptmerkmale sind: ein fortschrittliches statisches Typsystem mit Typinferenz; Funktionstypen; Mustervergleich; implizite Parameter und Konvertierungen; Überlastung des Bedieners; volle Interoperabilität mit Java; Parallelität