I have a question about a correct way work with IO blocking operations, i read that the right model it's wrap blocking actions into Future
and work with this object instead of call blocking operations inside actor.
But i see this have as minimum two solutions
case class AccountBalance(id: Int, userId: Int, total: Int)
object AccountBalance {
def getUserAccountBalance(userId: Int)(
implicit ec: ExecutionContext): Future[AccountBalance] = {
Future {
AccountBalance(1, userId, 1)
}
}
def updateAccountBalance(id: Int, total: Int)(implicit ec: ExecutionContext): Future[AccountBalance] = {
Future {
AccountBalance(id, 1, total)
}
}
// Main logic
def getAndInc(userId: Int)(implicit ec: ExecutionContext) = {
getUserAccountBalance(userId).flatMap { balance =>
updateAccountBalance(balance.id, balance.total + 1)
}
}
}
In first approach i use AccountBalanece.getAndInc
method inside actor:
class Approach1 extends Actor {
implicit val executionContext = context.dispatcher
def receive = {
case Calculate(userId) =>
AccountBalance.getAndInc(userId) pipeTo sender
}
}
For another solution (more comfortable for me)
class Approach2 extends Actor {
implicit val executionContext = context.dispatcher
var firstSender: ActorRef = null
var userId: Int = -1
def receive = {
case Calculate(givenUserId) =>
userId = givenUserId
firstSender = sender
AccountBalance.getUserAccountBalance(userId) pipeTo self
case AccountBalance(id, _, total) =>
AccountBalance.updateAccountBalance(id, total + 1) pipeTo firstSender
}
}
What solution is better (or both dangerous and not usable)?
And second question about ExecutionContext
, for examples i use context.dispatcher
for real application i use the next:
class A extends Actor {
implicit val executionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10))
override def postStop = {
executionContext.shutdown()
}
def receive = { case _ => }
}
If i use executionContext.shutdown
after actor is stopped, this is correct way to shutdown thread pool and free all resources?
答案 0 :(得分:0)
因为需要反应式编程定义以确保不阻止执行线程。因此,任何阻塞操作都应该由不同的执行上下文来处理,以便不阻止调度actor命令/消息的线程。我使用我演员正在使用的第二种模式"成为"并转到不同的行为,等待阻止操作的响应。希望不处理任何新请求并丢失原始发送者actorRef。如果您仍希望演员接收其他消息并发送,则需要在原始发件人和收到的回复之间建立链接。
是的,以这种方式停止,会起作用,但我建议在创建线程池时要非常小心,并在阻塞actor之间共享它们。如果关闭引发异常并且您只想关闭actor A而不是所有akka系统,请注意主管A不会被主管重新启动。