我是Akka的初学者。我需要每天在固定的时间安排一项任务,比如上午8点。我所知道的是定期安排任务,例如
import akka.util.duration._
scheduler.schedule(0 seconds, 10 minutes) {
doSomething()
}
在Akka的一天中的固定时间安排任务的最简单方法是什么?
使用此功能很容易做我想要的事情。玩具实现看起来像
scheduler.schedule(0 seconds, 24 hours) {
val now = computeTimeOfDay()
val delay = desiredTime - now
scheduler.scheduleOnce(delay) {
doSomething()
}
}
这并不难,但我介绍了一点竞争条件。事实上,考虑一下如果我在上午8点之前启动它会发生什么。外部闭包将开始,但到我计算delay
时,我们可能会在上午8点之后。这意味着内部关闭 - 应立即执行 - 将推迟到明天,从而跳过执行一天。
有一些方法可以解决这种竞争条件:例如,我可以每12小时执行一次检查,而不是立即安排任务,将其发送给一次不接受多个任务的演员。 / p>
但可能,这已经存在于Akka或某些扩展中。
答案 0 :(得分:6)
要在Akka中使用这种计划,您必须自己动手或使用Quartz,可以通过Akka Camel或prototype quartz for akka。
如果你不需要任何花哨和非常准确的东西,那么我只计算第一次所需的延迟,并将其作为计划调用的开始延迟,并信任间隔。
答案 1 :(得分:5)
写一次,每天跑步
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)
}
我相信Akka的调度程序会以某种方式内部处理重启。我使用非持久的方式向自己发送消息 - 实际上没有严格的交付保证。此外,滴答可能会有所不同,因此GatherStatisticsPeriod可能是一个函数。
答案 2 :(得分:4)
我们假设您希望每天下午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())
另请注意,服务器时区可能与您的不同。
答案 3 :(得分:0)
只需添加另一种实现方法,就可以使用Akka Streams通过ticking一条消息并按时进行过滤。
Source
.tick(0.seconds, 2.seconds, "hello") // emits "hello" every two seconds
.filter(_ => {
val now = LocalDateTime.now.getSecond
now > 20 && now < 30 // will let through only if the timing is right.
})
.runForeach(n => println("final sink received " + n))