繁体   English   中英

无阻塞计时器任务和Akka Actor

[英]Non-Blocking Timer Tasks and Akka Actors

请注意:尽管我更喜欢使用Akka的Java API的解决方案(这是我正在使用的解决方案),但我对任何可行的解决方案都感到满意,并且可能会想出如何将基于Scala的答案转换为Java语言。


我有一个具有许多演员的Akka应用程序,其中两个是FizzBuzz Fizz演员可以接受两种类型的消息:

  • StartNewTimerTask ;
  • ResetAllTimerTasks

Buzz演员仅接受DoItNow消息。 这些参与者与系统其余部分之间的消息流如下:

  1. 任何东西(其他参与者,甚至参与者系统外部的事件驱动组件)都可以随时将StartNewTimerTask消息发送给Fizz参与者
  2. 每次Fizz actor收到StartNewTimerTask消息时,它都会创建并启动一个新的异步/非阻塞计时器,该计时器尝试运行8秒。 如果计时器结束(8秒),则将DoItNow消息发送给Buzz actor
  3. Fizz演员可以接受任意数量的并发StartNewTimerTask消息,因此,可以同时“管理”多个潜在的计时器,每个计时器都计入该8秒的神奇数字。 其他因此,如果20名演员StartNewTimerTask消息的Fizz演员都彼此,那么几秒钟内Fizz演员将是“管理” 20无阻塞,在同一时间独立的定时器。 当这20个计时器中的每个计时器达到各自的8秒持续时间时,它们会向Buzz actor发送20条独立的DoItNow消息
  4. Fizz演员接收ResetAllTimerTasks消息时,当前正在“进行中” 的所有计时器将被中断/取消(以使它们停止向下计数到8秒的持续时间,从而防止它们从发送DoItNow消息Buzz )。 因此,从上面的示例中借用,如果Fizz actor在时间t=1t=3之间收到了20条StartNewTimerTask消息,则在t=10可能已经过去了14个定时器并触发了DoItNow消息,也许还有6个正在进行中。 如果Fizz在那一刻接收到ResetAllTimerTasks消息,它将停止这6个计时器的ResetAllTimerTasks和触发消息,因此在此示例中Buzz将仅接收14条DoItNow消息

我知道Java 8 API(sans Akka)提倡扩展TimerTask并将这些任务提交给Timer#scheduleAtFixedRate方法,但是我不确定这是否与Akka完全冲突,或者是否有更好的方法来实现此功能Akka API。 迄今为止我最大的尝试:

// Groovy pseudo-code
class MyTimerTask extends TimerTask {
  @Inject
  ActorRef buzz

  @Override
  void run() {
    // No op!
  }

  void completeTask() {
    buzz.tell(new DoItNow(), null)
  }
}

class Fizz extends UntypedAbstractActor {
  @Inject
  Timer timer

  @Override
  void onReceive(Object message) {
    if(message in StartNewTimerTask) {
      timer.scheduleAtFixedRate(new MyTimerTask(), 0, 8 * 1000)
    } else if(message in ResetAllTimerTasks) {
      timer.cancel()
    }
  }
}

class Buzz extends UntypedAbstractActor {
  @Override
  void onReceive(Object message) {
    if(message in DoItNow) {
      // Do something super cool now...
    }
  }
}

但是我认为我没有正确地管理计时器,也没有充分利用Akka调度程序/计时器API的全部潜能。 有什么想法吗?

考虑避开Java Timer API,以支持Akka 2.5.4刚发布的新的actor定时器功能。 Actor计时器使Actor可以使用与其生命周期相关的一个或多个内部计时器来安排向其发送定期消息。 要使用Java访问此功能,只需更改Fizz actor即可扩展AbstractActorWithTimers

下面的示例在Scala中(在Scala中,混合使用Timers特性):

object Fizz {
  private case object SendToBuzz
}

class Fizz(buzz: ActorRef) extends Actor with Timers {
  import Fizz._

  def receive = {
    case StartNewTimerTask =>
      val uuid = java.util.UUID.randomUUID
      timers.startPeriodicTimer(uuid, SendToBuzz, 8.seconds)
    case ResetAllTimerTasks =>
      timers.cancelAll()
    case SendToBuzz =>
      buzz ! DoItNow
  }
}
  • Fizz actor处理StartNewTimerTask消息时,它将启动一个新计时器,该计时器将每八秒向self (即Fizz actor)发送一次SendToBuzz消息。
  • Fizz处理SendToBuzz消息时,会将DoItNow消息发送给Buzz actor。
  • Fizz处理ResetAllTimerTasks消息时,它将取消所有计时器。
  • 如果Fizz重新启动或停止,则其所有计时器都会自动取消。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM