Akka (Scala) - 如何正确重置计时器/调度程序?
Akka (Scala) - how to properly reset timer / scheduler?
我必须填写模板以实现购物车超时。到目前为止我有:
import akka.actor.{Actor, ActorRef, Cancellable, Props, Timers}
import akka.event.{Logging, LoggingReceive}
import scala.concurrent.duration._
import scala.language.postfixOps
object CartActor {
sealed trait Command
case class AddItem(item: Any) extends Command
case class RemoveItem(item: Any) extends Command
case object ExpireCart extends Command
case object StartCheckout extends Command
case object ConfirmCheckoutCancelled extends Command
case object ConfirmCheckoutClosed extends Command
sealed trait Event
case class CheckoutStarted(checkoutRef: ActorRef) extends Event
def props = Props(new CartActor())
}
class CartActor extends Actor with Timers {
import context._
import CartActor._
private val log = Logging(context.system, this)
val cartTimerDuration: FiniteDuration = 5 seconds
var cart: Cart = Cart.empty
private def scheduleTimer: Cancellable =
system.scheduler.scheduleOnce(cartTimerDuration, self, ExpireCart)
def receive: Receive = empty
def empty: Receive = {
case AddItem(item) =>
this.cart = cart.addItem(item)
scheduleTimer
context become nonEmpty(cart, scheduleTimer)
case _ =>
}
def nonEmpty(cart: Cart, timer: Cancellable): Receive = {
case AddItem(item) =>
this.cart = cart.addItem(item)
timer.cancel()
scheduleTimer
case RemoveItem(item) =>
this.cart = this.cart.removeItem(item)
if (this.cart.size != 0) {
timer.cancel()
scheduleTimer
}
else
context become empty
case StartCheckout =>
context become inCheckout(this.cart)
case ExpireCart =>
this.cart = Cart.empty
println("Cart expired")
context become empty
}
def inCheckout(cart: Cart): Receive = {
case ConfirmCheckoutCancelled =>
context become nonEmpty(cart, scheduleTimer)
case ConfirmCheckoutClosed =>
println("Cart closed after checkout")
context become empty
case _ =>
}
}
提供了方法签名,例如我无法更改 def nonEmpty(cart: Cart, timer: Cancellable)
。添加或删除项目时,应重置计时器,以便用户再次有 5 秒的时间做某事。问题是我不知道如何正确地做到这一点——上面的方法显然不会重置计时器,因为它总是在 5 秒后超时。
我怎样才能做到这一点?我应该使用计时器而不是调度程序,例如timers.startSingleTimer("ExpireCart", ExpireCart, cartTimerDuration)
?我应该如何在方法之间传递它?计时器是否应该改为 CartActor 的属性,而我应该忽略调度程序?附带一提,当我有 def nonEmpty(cart: Cart, timer: Cancellable)
时,计时器是在任何地方隐式调用,还是只是传递?
有两个问题。
首先,在 empty
中您启动了两个计时器:
scheduleTimer // Creates a timer, reference lost so can't be cancelled
context become nonEmpty(cart, scheduleTimer) // Creates a second timer
更一般地说,您在接收方法中使用可变状态 和 参数。不需要可变状态,因此删除此行:
var cart: Cart = Cart.empty
现在修复 nonEmpty
以将更新后的状态传递给新的 receive
方法,而不是使用 this
:
def nonEmpty(cart: Cart, timer: Cancellable): Receive = {
case AddItem(item) =>
timer.cancel()
context become nonEmpty(cart.addItem(item), scheduleTimer)
case RemoveItem(item) =>
timer.cancel()
if (this.cart.size > 1) {
context become nonEmpty(cart.remoteItem(item), scheduleTimer)
} else {
context become empty
}
case StartCheckout =>
timer.cancel()
context become inCheckout(cart)
case ExpireCart =>
timer.cancel() // Just in case :)
println("Cart expired")
context become empty
}
我必须填写模板以实现购物车超时。到目前为止我有:
import akka.actor.{Actor, ActorRef, Cancellable, Props, Timers}
import akka.event.{Logging, LoggingReceive}
import scala.concurrent.duration._
import scala.language.postfixOps
object CartActor {
sealed trait Command
case class AddItem(item: Any) extends Command
case class RemoveItem(item: Any) extends Command
case object ExpireCart extends Command
case object StartCheckout extends Command
case object ConfirmCheckoutCancelled extends Command
case object ConfirmCheckoutClosed extends Command
sealed trait Event
case class CheckoutStarted(checkoutRef: ActorRef) extends Event
def props = Props(new CartActor())
}
class CartActor extends Actor with Timers {
import context._
import CartActor._
private val log = Logging(context.system, this)
val cartTimerDuration: FiniteDuration = 5 seconds
var cart: Cart = Cart.empty
private def scheduleTimer: Cancellable =
system.scheduler.scheduleOnce(cartTimerDuration, self, ExpireCart)
def receive: Receive = empty
def empty: Receive = {
case AddItem(item) =>
this.cart = cart.addItem(item)
scheduleTimer
context become nonEmpty(cart, scheduleTimer)
case _ =>
}
def nonEmpty(cart: Cart, timer: Cancellable): Receive = {
case AddItem(item) =>
this.cart = cart.addItem(item)
timer.cancel()
scheduleTimer
case RemoveItem(item) =>
this.cart = this.cart.removeItem(item)
if (this.cart.size != 0) {
timer.cancel()
scheduleTimer
}
else
context become empty
case StartCheckout =>
context become inCheckout(this.cart)
case ExpireCart =>
this.cart = Cart.empty
println("Cart expired")
context become empty
}
def inCheckout(cart: Cart): Receive = {
case ConfirmCheckoutCancelled =>
context become nonEmpty(cart, scheduleTimer)
case ConfirmCheckoutClosed =>
println("Cart closed after checkout")
context become empty
case _ =>
}
}
提供了方法签名,例如我无法更改 def nonEmpty(cart: Cart, timer: Cancellable)
。添加或删除项目时,应重置计时器,以便用户再次有 5 秒的时间做某事。问题是我不知道如何正确地做到这一点——上面的方法显然不会重置计时器,因为它总是在 5 秒后超时。
我怎样才能做到这一点?我应该使用计时器而不是调度程序,例如timers.startSingleTimer("ExpireCart", ExpireCart, cartTimerDuration)
?我应该如何在方法之间传递它?计时器是否应该改为 CartActor 的属性,而我应该忽略调度程序?附带一提,当我有 def nonEmpty(cart: Cart, timer: Cancellable)
时,计时器是在任何地方隐式调用,还是只是传递?
有两个问题。
首先,在 empty
中您启动了两个计时器:
scheduleTimer // Creates a timer, reference lost so can't be cancelled
context become nonEmpty(cart, scheduleTimer) // Creates a second timer
更一般地说,您在接收方法中使用可变状态 和 参数。不需要可变状态,因此删除此行:
var cart: Cart = Cart.empty
现在修复 nonEmpty
以将更新后的状态传递给新的 receive
方法,而不是使用 this
:
def nonEmpty(cart: Cart, timer: Cancellable): Receive = {
case AddItem(item) =>
timer.cancel()
context become nonEmpty(cart.addItem(item), scheduleTimer)
case RemoveItem(item) =>
timer.cancel()
if (this.cart.size > 1) {
context become nonEmpty(cart.remoteItem(item), scheduleTimer)
} else {
context become empty
}
case StartCheckout =>
timer.cancel()
context become inCheckout(cart)
case ExpireCart =>
timer.cancel() // Just in case :)
println("Cart expired")
context become empty
}