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

@ -151,7 +151,7 @@ public class FaultHandlingDocSample {
getContext()
.getSystem()
.scheduler()
.schedule(
.scheduleWithFixedDelay(
Duration.ZERO,
Duration.ofSeconds(1L),
getSelf(),

View file

@ -5,8 +5,6 @@
package jdocs.actor;
// #imports1
import akka.actor.Props;
import jdocs.AbstractJavaTest;
import java.time.Duration;
// #imports1
@ -14,6 +12,8 @@ import java.time.Duration;
import akka.actor.Cancellable;
// #imports2
import jdocs.AbstractJavaTest;
import akka.actor.Props;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
@ -35,7 +35,8 @@ public class SchedulerDocTest extends AbstractJavaTest {
// #schedule-one-off-message
system
.scheduler()
.scheduleOnce(Duration.ofMillis(50), testActor, "foo", system.dispatcher(), null);
.scheduleOnce(
Duration.ofMillis(50), testActor, "foo", system.dispatcher(), ActorRef.noSender());
// #schedule-one-off-message
// #schedule-one-off-thunk
@ -76,8 +77,13 @@ public class SchedulerDocTest extends AbstractJavaTest {
Cancellable cancellable =
system
.scheduler()
.schedule(
Duration.ZERO, Duration.ofMillis(50), tickActor, "Tick", system.dispatcher(), null);
.scheduleWithFixedDelay(
Duration.ZERO,
Duration.ofMillis(50),
tickActor,
"Tick",
system.dispatcher(),
ActorRef.noSender());
// This cancels further Ticks to be sent
cancellable.cancel();

View file

@ -33,7 +33,7 @@ public class TimerDocTest {
FirstTick.class,
message -> {
// do something useful here
getTimers().startPeriodicTimer(TICK_KEY, new Tick(), Duration.ofSeconds(1));
getTimers().startTimerWithFixedDelay(TICK_KEY, new Tick(), Duration.ofSeconds(1));
})
.match(
Tick.class,

View file

@ -79,7 +79,10 @@ public class FSMDocTest extends AbstractJavaTest {
// #transition-syntax
onTransition(
matchState(Idle, Active, () -> setTimer("timeout", Tick, Duration.ofSeconds(1L), true))
matchState(
Idle,
Active,
() -> startTimerWithFixedDelay("timeout", Tick, Duration.ofSeconds(1L)))
.state(Active, null, () -> cancelTimer("timeout"))
.state(null, Idle, (f, t) -> log().info("entering Idle from " + f)));
// #transition-syntax

View file

@ -43,7 +43,8 @@ public class StatsSampleClient extends AbstractActor {
getContext()
.getSystem()
.scheduler()
.schedule(interval, interval, getSelf(), "tick", getContext().getDispatcher(), null);
.scheduleWithFixedDelay(
interval, interval, getSelf(), "tick", getContext().getDispatcher(), null);
}
// subscribe to cluster changes, MemberEvent

View file

@ -37,7 +37,7 @@ public class DataBot extends AbstractActor {
getContext()
.getSystem()
.scheduler()
.schedule(
.scheduleWithFixedDelay(
Duration.ofSeconds(5),
Duration.ofSeconds(5),
getSelf(),

View file

@ -79,7 +79,7 @@ public class RecipeGlobalRateLimit extends RecipeTest {
this.replenishTimer =
system
.scheduler()
.schedule(
.scheduleWithFixedDelay(
this.tokenRefreshPeriod,
this.tokenRefreshPeriod,
getSelf(),