使用Akka在一天中的固定时间安排任务

And*_*rea 19 scala scheduled-tasks akka

我是Akka的初学者.我需要每天在固定的时间安排一项任务,比如上午8点.我所知道的是如何定期安排任务

import akka.util.duration._

scheduler.schedule(0 seconds, 10 minutes) {
  doSomething()
}
Run Code Online (Sandbox Code Playgroud)

在Akka一天中的固定时间安排任务的最简单方法是什么?

一个小括号

只需使用此功能就可以轻松完成我想要的操作.玩具实现看起来像

scheduler.schedule(0 seconds, 24 hours) {
  val now = computeTimeOfDay()
  val delay = desiredTime - now

  scheduler.scheduleOnce(delay) {
    doSomething()
  }
}
Run Code Online (Sandbox Code Playgroud)

这并不难,但我介绍了一点竞争条件.事实上,考虑如果我在上午8点之前启动它会发生什么.外部闭合将开始,但到我计算时,delay我们可能会在上午8点之后.这意味着内部关闭 - 应该立即执行 - 将被推迟到明天,从而跳过执行一天.

有办法解决这种竞争条件:例如,我可以每12小时执行一次检查,而不是立即安排任务,将其发送给一次不接受多个任务的演员.

但可能,这已经存在于Akka或某些扩展中.

ido*_*nie 7

写一次,每天跑

val GatherStatisticsPeriod = 24 hours

private[this] val scheduled = new AtomicBoolean(false)

def calcBeforeMidnight: Duration = { 
  // TODO implement 
} 

def preRestart(reason: Throwable, message: Option[Any]) {
  self ! GatherStatisticsScheduled(scheduled.get)
  super.preRestart(reason, message)
}

def schedule(period: Duration, who: ActorRef) = 
  ServerRoot.actorSystem.scheduler
    .scheduleOnce(period)(who ! GatherStatisticsTick)

def receive = {

  case StartServer(nodeName) => 
    sender ! ServerStarted(nodeName)
    if (scheduled.compareAndSet(false, true)) 
      schedule(calcBeforeMidnight, self)

  case GatherStatisticsTick =>
    stats.update
    scheduled.set(true)
    schedule(GatherStatisticsPeriod, self) 

  case GatherStatisticsScheduled(isScheduled) =>
    if (isScheduled && scheduled.compareAndSet(false, isScheduled))
      schedule(calcBeforeMidnight, self)

}
Run Code Online (Sandbox Code Playgroud)

我相信Akka的调度程序会以某种方式内部处理重启.我使用非持久的方式向自己发送消息 - 实际上没有严格的交付保证.此外,滴答可能会有所不同,因此GatherStatisticsPeriod可能是一个函数.


Bjö*_*son 6

要在Akka中使用这种调度,您必须自己滚动或者通过Akka Camel用于Akka的原型石英使用Quartz 。

如果您不需要任何花哨且非常准确的方法,那么我只需计算所需的第一次延迟,并将其用作计划调用的开始延迟,并信任该间隔。

  • 是的,调度程序将长期保持准确。就像System.nanoTime一样准确,并且调度程序的配置在akka配置中打勾`akka.scheduler.tick-duration`。 (2认同)

Pav*_*tou 5

假设您想每天下午13点运行任务。

import scala.concurrent.duration._
import java.time.LocalTime

val interval = 24.hours
val delay = {
  val time = LocalTime.of(13, 0).toSecondOfDay
  val now = LocalTime.now().toSecondOfDay
  val fullDay = 60 * 60 * 24
  val difference = time - now
  if (difference < 0) {
    fullDay + difference
  } else {
    time - now
  }
}.seconds

system.scheduler.schedule(delay, interval)(doSomething())
Run Code Online (Sandbox Code Playgroud)

还请记住,服务器时区可能与您的时区不同。