scheduleWithFixedDelay vs scheduleAtFixedRate, #26910

* previous `schedule` method is trying to maintain a fixed average frequency
  over time, but that can result in undesired bursts of scheduled tasks after a long
  GC or if the JVM process has been suspended, same with all other periodic
  scheduled message sending via various Timer APIs
* most of the time "fixed delay" is more desirable
* we can't just change because it's too big behavioral change and some might
  depend on previous behavior
* deprecate the old `schedule` and introduce new `scheduleWithFixedDelay`
  and `scheduleAtFixedRate`, when fixing the deprecation warning users should
  make a concious decision of which behavior to use (scheduleWithFixedDelay in
  most cases)

* Streams
* SchedulerSpec
  * test both fixed delay and fixed rate
* TimerSpec
* FSM and PersistentFSM
* mima
* runnable as second parameter list, also in typed.Scheduler
* IllegalStateException vs SchedulerException
* deprecated annotations
* api and reference docs, all places
* migration guide
This commit is contained in:
Patrik Nordwall 2019-05-27 11:53:26 +02:00
parent 72cfc2485e
commit 10d32fceb9
99 changed files with 2285 additions and 909 deletions

View file

@ -116,7 +116,7 @@ class FSMDocSpec extends MyFavoriteTestFrameWorkPlusAkkaTestKit {
//#transition-syntax
onTransition {
case Idle -> Active => setTimer("timeout", Tick, 1 second, repeat = true)
case Idle -> Active => startTimerWithFixedDelay("timeout", Tick, 1 second)
case Active -> _ => cancelTimer("timeout")
case x -> Idle => log.info("entering Idle from " + x)
}

View file

@ -97,7 +97,7 @@ class Worker extends Actor with ActorLogging {
def receive = LoggingReceive {
case Start if progressListener.isEmpty =>
progressListener = Some(sender())
context.system.scheduler.schedule(Duration.Zero, 1 second, self, Do)
context.system.scheduler.scheduleWithFixedDelay(Duration.Zero, 1 second, self, Do)
case Do =>
counterService ! Increment(1)

View file

@ -54,7 +54,7 @@ class SchedulerDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
//This will schedule to send the Tick-message
//to the tickActor after 0ms repeating every 50ms
val cancellable =
system.scheduler.schedule(0 milliseconds, 50 milliseconds, tickActor, Tick)
system.scheduler.scheduleWithFixedDelay(Duration.Zero, 50.milliseconds, tickActor, Tick)
//This cancels further Ticks to be sent
cancellable.cancel()

View file

@ -24,7 +24,7 @@ object TimerDocSpec {
def receive = {
case FirstTick =>
// do something useful here
timers.startPeriodicTimer(TickKey, Tick, 1.second)
timers.startTimerWithFixedDelay(TickKey, Tick, 1.second)
case Tick =>
// do something useful here
}

View file

@ -55,7 +55,7 @@ object TransformationFrontend {
val counter = new AtomicInteger
import system.dispatcher
system.scheduler.schedule(2.seconds, 2.seconds) {
system.scheduler.scheduleWithFixedDelay(2.seconds, 2.seconds) { () =>
implicit val timeout = Timeout(5 seconds)
(frontend ? TransformationJob("hello-" + counter.incrementAndGet())).foreach { result =>
println(result)

View file

@ -66,7 +66,7 @@ object DistributedDataDocSpec {
implicit val node = DistributedData(context.system).selfUniqueAddress
import context.dispatcher
val tickTask = context.system.scheduler.schedule(5.seconds, 5.seconds, self, Tick)
val tickTask = context.system.scheduler.scheduleWithFixedDelay(5.seconds, 5.seconds, self, Tick)
val DataKey = ORSetKey[String]("key")

View file

@ -36,7 +36,7 @@ class MyEventsByTagSource(tag: String, offset: Long, refreshInterval: FiniteDura
private val serialization = SerializationExtension(system)
override def preStart(): Unit = {
schedulePeriodically(Continue, refreshInterval)
scheduleWithFixedDelay(Continue, refreshInterval, refreshInterval)
}
override def onPull(): Unit = {

View file

@ -37,9 +37,9 @@ class RecipeGlobalRateLimit extends RecipeSpec {
private var waitQueue = immutable.Queue.empty[ActorRef]
private var permitTokens = maxAvailableTokens
private val replenishTimer = system.scheduler.schedule(
private val replenishTimer = system.scheduler.scheduleWithFixedDelay(
initialDelay = tokenRefreshPeriod,
interval = tokenRefreshPeriod,
delay = tokenRefreshPeriod,
receiver = self,
ReplenishTokens)

View file

@ -154,7 +154,7 @@ class TestKitDocSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
assert(fsm.stateName == 1)
assert(fsm.isTimerActive("test") == false)
fsm.setTimer("test", 12, 10 millis, true)
fsm.startTimerWithFixedDelay("test", 12, 10 millis)
assert(fsm.isTimerActive("test") == true)
fsm.cancelTimer("test")
assert(fsm.isTimerActive("test") == false)