Akka:将响应发回给 Actor
Akka: send back response to Actor
我有以下代码向发送方 Actor 发回响应(响应 actor 使用 Slick 从 table 加载列表):
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
}
}
这里的问题是 loadUsers
returns 在等待 Future 完成之前。如何解决这个问题?
你应该使用 pipe pattern:
import akka.pattern.pipe
// ...
def receive = {
val originalSender = sender
loadUsers pipeTo originalSender
}
Jean Logeart 已经提到了概念性解决方案。关于 loadUsers,我认为这是一个较短的版本?
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
}
如我所见,最简单的方法是简单地将 future
发送回 sender
,而不是 async-filled list
.
如
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
}
现在调用方 actor 有处理未来或失败的负担。
这也有缺点,如果 sender
使用 ask
/?
操作,异步结果将是 Future
包装进一步的 Future
.
您可以使用 pipeTo
方法解决这个问题,该方法将未来的消息发送给调用者,而无需费心解包。
piping 结果的缺点是 sender
应该有办法识别哪个回复属于哪个请求。一个可能的解决方案是发送一个请求标识符,该标识符将与答案一起发回,因此请求者可以轻松地 link 两者。
旁注
为什么要在未来的结果中映射 firstName
属性,而不是在 slick 查询中使用投影?我假设这是为了让示例保持简单。
我有以下代码向发送方 Actor 发回响应(响应 actor 使用 Slick 从 table 加载列表):
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
}
}
这里的问题是 loadUsers
returns 在等待 Future 完成之前。如何解决这个问题?
你应该使用 pipe pattern:
import akka.pattern.pipe
// ...
def receive = {
val originalSender = sender
loadUsers pipeTo originalSender
}
Jean Logeart 已经提到了概念性解决方案。关于 loadUsers,我认为这是一个较短的版本?
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
}
如我所见,最简单的方法是简单地将 future
发送回 sender
,而不是 async-filled list
.
如
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
}
现在调用方 actor 有处理未来或失败的负担。
这也有缺点,如果 sender
使用 ask
/?
操作,异步结果将是 Future
包装进一步的 Future
.
您可以使用 pipeTo
方法解决这个问题,该方法将未来的消息发送给调用者,而无需费心解包。
piping 结果的缺点是 sender
应该有办法识别哪个回复属于哪个请求。一个可能的解决方案是发送一个请求标识符,该标识符将与答案一起发回,因此请求者可以轻松地 link 两者。
旁注
为什么要在未来的结果中映射 firstName
属性,而不是在 slick 查询中使用投影?我假设这是为了让示例保持简单。