Add convenience method to start timer without key (#27875)

* Add convenience method to start timer without key

It is probably common that there is no need to allow different timers
that send the same message, and this makes that more convenient to write.

Updated one method to gather feedback, if we like the change I can apply
it to the others as well.

* Add alternative to all typed timer API's

Update java/scaladoc, update tests

Not updated classic actors and FSM API's
This commit is contained in:
Arnout Engelen 2019-11-26 14:26:49 +01:00 committed by Christopher Batey
parent 38d41e11fb
commit 4b632c4537
21 changed files with 253 additions and 116 deletions

View file

@ -30,7 +30,11 @@ public class ManualTimerExampleTest extends JUnitSuite {
private final ManualTime manualTime = ManualTime.get(testKit.system());
static final class Tick {}
static final class Tick {
private Tick() {}
static final Tick INSTANCE = new Tick();
}
static final class Tock {}
@ -40,7 +44,7 @@ public class ManualTimerExampleTest extends JUnitSuite {
Behavior<Tick> behavior =
Behaviors.withTimers(
timer -> {
timer.startSingleTimer("T", new Tick(), Duration.ofMillis(10));
timer.startSingleTimer(Tick.INSTANCE, Duration.ofMillis(10));
return Behaviors.receiveMessage(
tick -> {
probe.ref().tell(new Tock());

View file

@ -47,7 +47,7 @@ class TestProbeSpec extends ScalaTestWithActorTestKit with WordSpecLike with Log
val probe = TestProbe()
val ref = spawn(Behaviors.receive[Stop.type]((_, _) =>
Behaviors.withTimers { timer =>
timer.startSingleTimer("key", Stop, 300.millis)
timer.startSingleTimer(Stop, 300.millis)
Behaviors.receive((_, _) => Behaviors.stopped)
}))

View file

@ -25,7 +25,7 @@ class ManualTimerExampleSpec extends ScalaTestWithActorTestKit(ManualTime.config
val probe = TestProbe[Tock.type]()
val behavior = Behaviors.withTimers[Tick.type] { timer =>
timer.startSingleTimer("T", Tick, 10.millis)
timer.startSingleTimer(Tick, 10.millis)
Behaviors.receiveMessage { _ =>
probe.ref ! Tock
Behaviors.same
@ -49,7 +49,7 @@ class ManualTimerExampleSpec extends ScalaTestWithActorTestKit(ManualTime.config
val probe = TestProbe[Tock.type]()
val behavior = Behaviors.withTimers[Tick.type] { timer =>
timer.startTimerWithFixedDelay("T", Tick, 10.millis)
timer.startTimerWithFixedDelay(Tick, 10.millis)
Behaviors.receiveMessage { _ =>
probe.ref ! Tock
Behaviors.same

View file

@ -133,6 +133,15 @@ public class ActorCompile {
});
}
{
Behavior<MyMsg> b =
Behaviors.withTimers(
timers -> {
timers.startTimerWithFixedDelay(new MyMsgB("tick"), Duration.ofSeconds(1));
return Behaviors.ignore();
});
}
static class MyBehavior extends ExtensibleBehavior<MyMsg> {
@Override

View file

@ -211,7 +211,7 @@ interface StyleGuideDocExamples {
name,
command.interval,
n);
timers.startTimerWithFixedDelay("repeat", Increment.INSTANCE, command.interval);
timers.startTimerWithFixedDelay(Increment.INSTANCE, command.interval);
return Behaviors.same();
}
@ -306,7 +306,7 @@ interface StyleGuideDocExamples {
setup.name,
command.interval,
n);
setup.timers.startTimerWithFixedDelay("repeat", Increment.INSTANCE, command.interval);
setup.timers.startTimerWithFixedDelay(Increment.INSTANCE, command.interval);
return Behaviors.same();
}
@ -394,7 +394,7 @@ interface StyleGuideDocExamples {
name,
command.interval,
n);
timers.startTimerWithFixedDelay("repeat", Increment.INSTANCE, command.interval);
timers.startTimerWithFixedDelay(Increment.INSTANCE, command.interval);
return Behaviors.same();
}
@ -552,7 +552,7 @@ interface StyleGuideDocExamples {
context ->
Behaviors.withTimers(
timers -> {
timers.startTimerWithFixedDelay("tick", Tick.INSTANCE, tickInterval);
timers.startTimerWithFixedDelay(Tick.INSTANCE, tickInterval);
return new Counter(name, context);
}));
}
@ -688,7 +688,7 @@ interface StyleGuideDocExamples {
(ActorContext<Message> context) ->
Behaviors.withTimers(
timers -> {
timers.startTimerWithFixedDelay("tick", Tick.INSTANCE, tickInterval);
timers.startTimerWithFixedDelay(Tick.INSTANCE, tickInterval);
return new Counter(name, context);
}))
.narrow(); // note narrow here

View file

@ -88,7 +88,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"schedule non-repeated ticks" taggedAs TimingTest in {
val probe = TestProbe[Event]("evt")
val behv = Behaviors.withTimers[Command] { timer =>
timer.startSingleTimer("T", Tick(1), 10.millis)
timer.startSingleTimer(Tick(1), 10.millis)
target(probe.ref, timer, 1)
}
@ -103,7 +103,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"schedule repeated ticks" taggedAs TimingTest in {
val probe = TestProbe[Event]("evt")
val behv = Behaviors.withTimers[Command] { timer =>
timer.startTimerWithFixedDelay("T", Tick(1), interval)
timer.startTimerWithFixedDelay(Tick(1), interval)
target(probe.ref, timer, 1)
}
@ -121,7 +121,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"replace timer" taggedAs TimingTest in {
val probe = TestProbe[Event]("evt")
val behv = Behaviors.withTimers[Command] { timer =>
timer.startTimerWithFixedDelay("T", Tick(1), interval)
timer.startTimerWithFixedDelay(Tick(1), interval)
target(probe.ref, timer, 1)
}
@ -141,7 +141,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"cancel timer" taggedAs TimingTest in {
val probe = TestProbe[Event]("evt")
val behv = Behaviors.withTimers[Command] { timer =>
timer.startTimerWithFixedDelay("T", Tick(1), interval)
timer.startTimerWithFixedDelay(Tick(1), interval)
target(probe.ref, timer, 1)
}
@ -193,7 +193,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
val probe = TestProbe[Event]("evt")
val behv = Behaviors
.supervise(Behaviors.withTimers[Command] { timer =>
timer.startTimerWithFixedDelay("T", Tick(1), interval)
timer.startTimerWithFixedDelay(Tick(1), interval)
target(probe.ref, timer, 1)
})
.onFailure[Exception](SupervisorStrategy.restart)
@ -222,7 +222,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"cancel timers when stopped from exception" taggedAs TimingTest in {
val probe = TestProbe[Event]()
val behv = Behaviors.withTimers[Command] { timer =>
timer.startTimerWithFixedDelay("T", Tick(1), interval)
timer.startTimerWithFixedDelay(Tick(1), interval)
target(probe.ref, timer, 1)
}
val ref = spawn(behv)
@ -235,7 +235,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"cancel timers when stopped voluntarily" taggedAs TimingTest in {
val probe = TestProbe[Event]()
val behv = Behaviors.withTimers[Command] { timer =>
timer.startTimerWithFixedDelay("T", Tick(1), interval)
timer.startTimerWithFixedDelay(Tick(1), interval)
target(probe.ref, timer, 1)
}
val ref = spawn(behv)
@ -246,9 +246,9 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"allow for nested timers" in {
val probe = TestProbe[String]()
val ref = spawn(Behaviors.withTimers[String] { outerTimer =>
outerTimer.startTimerWithFixedDelay("outer-key", "outer-message", 50.millis)
outerTimer.startTimerWithFixedDelay("outer-message", 50.millis)
Behaviors.withTimers { innerTimer =>
innerTimer.startTimerWithFixedDelay("inner-key", "inner-message", 50.millis)
innerTimer.startTimerWithFixedDelay("inner-message", 50.millis)
Behaviors.receiveMessage { message =>
if (message == "stop") Behaviors.stopped
else {
@ -273,7 +273,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
"keep timers when behavior changes" in {
val probe = TestProbe[String]()
def newBehavior(n: Int): Behavior[String] = Behaviors.withTimers[String] { timers =>
timers.startTimerWithFixedDelay(s"key${n}", s"message${n}", 50.milli)
timers.startTimerWithFixedDelay(s"message${n}", 50.milli)
Behaviors.receiveMessage { message =>
if (message == "stop") Behaviors.stopped
else {
@ -299,7 +299,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
val probe = TestProbe[DeadLetter]()
val ref = spawn(Behaviors.withTimers[String] { timers =>
Behaviors.setup { _ =>
timers.startTimerWithFixedDelay("test", "test", 250.millis)
timers.startTimerWithFixedDelay("test", 250.millis)
Behaviors.receive { (context, _) =>
Behaviors.stopped(() => context.log.info(s"stopping"))
}
@ -323,11 +323,11 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
case Tick(-1) =>
probe.ref ! Tock(-1)
Behaviors.withTimers[Command] { timer =>
timer.startSingleTimer("T0", Tick(0), 5.millis)
timer.startSingleTimer(Tick(0), 5.millis)
Behaviors.receiveMessage[Command] {
case Tick(0) =>
probe.ref ! Tock(0)
timer.startSingleTimer("T1", Tick(1), 5.millis)
timer.startSingleTimer(Tick(1), 5.millis)
// let Tick(0) arrive in mailbox, test will not fail if it arrives later
Thread.sleep(100)
throw TestException("boom")
@ -365,7 +365,7 @@ class TimerSpec extends ScalaTestWithActorTestKit with WordSpecLike with LogCapt
case Tick(-1) =>
probe.ref ! Tock(-1)
Behaviors.withTimers[Command] { timer =>
timer.startSingleTimer("T0", Tick(0), 5.millis)
timer.startSingleTimer(Tick(0), 5.millis)
// let Tick(0) arrive in mailbox, test will not fail if it arrives later
Thread.sleep(100)
throw TestException("boom")

View file

@ -148,7 +148,7 @@ class TransformMessagesSpec extends ScalaTestWithActorTestKit with WordSpecLike
val probe = TestProbe[String]()
val behv = Behaviors
.withTimers[String] { timers =>
timers.startSingleTimer("timer", "a", 10.millis)
timers.startSingleTimer("a", 10.millis)
Behaviors.receiveMessage { msg =>
probe.ref ! msg
Behaviors.same
@ -169,7 +169,7 @@ class TransformMessagesSpec extends ScalaTestWithActorTestKit with WordSpecLike
"be possible to combine with outer timers" in {
val probe = TestProbe[String]()
val behv = Behaviors.withTimers[String] { timers =>
timers.startSingleTimer("timer", "a", 10.millis)
timers.startSingleTimer("a", 10.millis)
Behaviors
.receiveMessage[String] { msg =>
probe.ref ! msg

View file

@ -57,7 +57,7 @@ object FSMDocSpec {
private def active(data: Todo): Behavior[Event] =
Behaviors.withTimers[Event] { timers =>
// instead of FSM state timeout
timers.startSingleTimer(Timeout, Timeout, 1.second)
timers.startSingleTimer(Timeout, 1.second)
Behaviors.receiveMessagePartial {
case Flush | Timeout =>
data.target ! Batch(data.queue)

View file

@ -123,7 +123,7 @@ object StyleGuideDocExamples {
name,
interval.toString,
n.toString)
timers.startTimerWithFixedDelay("repeat", Increment, interval)
timers.startTimerWithFixedDelay(Increment, interval)
Behaviors.same
case Increment =>
val newValue = n + 1
@ -166,7 +166,7 @@ object StyleGuideDocExamples {
setup.name,
interval,
n)
setup.timers.startTimerWithFixedDelay("repeat", Increment, interval)
setup.timers.startTimerWithFixedDelay(Increment, interval)
Behaviors.same
case Increment =>
val newValue = n + 1
@ -213,7 +213,7 @@ object StyleGuideDocExamples {
name,
interval,
n)
timers.startTimerWithFixedDelay("repeat", Increment, interval)
timers.startTimerWithFixedDelay(Increment, interval)
Behaviors.same
case Increment =>
val newValue = n + 1
@ -249,7 +249,7 @@ object StyleGuideDocExamples {
name,
interval,
n)
timers.startTimerWithFixedDelay("repeat", Increment, interval)
timers.startTimerWithFixedDelay(Increment, interval)
Behaviors.same
case Increment =>
val newValue = n + 1
@ -341,7 +341,7 @@ object StyleGuideDocExamples {
def apply(name: String, tickInterval: FiniteDuration): Behavior[Command] =
Behaviors.setup { context =>
Behaviors.withTimers { timers =>
timers.startTimerWithFixedDelay("tick", Tick, tickInterval)
timers.startTimerWithFixedDelay(Tick, tickInterval)
new Counter(name, context).counter(0)
}
}
@ -390,7 +390,7 @@ object StyleGuideDocExamples {
Behaviors
.setup[Counter.Message] { context =>
Behaviors.withTimers { timers =>
timers.startTimerWithFixedDelay("tick", Tick, tickInterval)
timers.startTimerWithFixedDelay(Tick, tickInterval)
new Counter(name, context).counter(0)
}
}

View file

@ -46,9 +46,9 @@ object TailChopping {
def sendNextRequest(requestCount: Int): Behavior[Command] = {
if (sendRequest(requestCount, replyAdapter)) {
timers.startSingleTimer(RequestTimeout, RequestTimeout, nextRequestAfter)
timers.startSingleTimer(RequestTimeout, nextRequestAfter)
} else {
timers.startSingleTimer(FinalTimeout, FinalTimeout, finalTimeout)
timers.startSingleTimer(FinalTimeout, finalTimeout)
}
waiting(requestCount)
}

View file

@ -29,12 +29,32 @@ trait TimerScheduler[T] {
* the reciprocal of the specified `delay`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerWithFixedDelay(key: Any, msg: T, delay: java.time.Duration): Unit
/**
* Schedules a message to be sent repeatedly to the `self` actor with a
* fixed `delay` between messages.
*
* It will not compensate the delay between messages if scheduling is delayed
* longer than specified for some reason. The delay between sending of subsequent
* messages will always be (at least) the given `delay`.
*
* In the long run, the frequency of messages will generally be slightly lower than
* the reciprocal of the specified `delay`.
*
* When a new timer is started with the same message,
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started. If you do not want this,
* you can start start them as individual timers by specifying distinct keys.
*/
def startTimerWithFixedDelay(msg: T, delay: java.time.Duration): Unit =
startTimerWithFixedDelay(msg, msg, delay)
/**
* Schedules a message to be sent repeatedly to the `self` actor with a
* given frequency.
@ -56,12 +76,41 @@ trait TimerScheduler[T] {
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerAtFixedRate(key: Any, msg: T, interval: java.time.Duration): Unit
/**
* Schedules a message to be sent repeatedly to the `self` actor with a
* given frequency.
*
* It will compensate the delay for a subsequent message if the sending of previous
* message was delayed more than specified. In such cases, the actual message interval
* will differ from the interval passed to the method.
*
* If the execution is delayed longer than the `interval`, the subsequent message will
* be sent immediately after the prior one. This also has the consequence that after
* long garbage collection pauses or other reasons when the JVM was suspended all
* "missed" messages will be sent when the process wakes up again.
*
* In the long run, the frequency of messages will be exactly the reciprocal of the
* specified `interval`.
*
* Warning: `startTimerAtFixedRate` can result in bursts of scheduled messages after long
* garbage collection pauses, which may in worst case cause undesired load on the system.
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* When a new timer is started with the same message,
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started. If you do not want this,
* you can start start them as individual timers by specifying distinct keys.
*/
def startTimerAtFixedRate(msg: T, interval: java.time.Duration): Unit =
startTimerAtFixedRate(msg, msg, interval)
/**
* Deprecated API: See [[TimerScheduler#startTimerWithFixedDelay]] or [[TimerScheduler#startTimerAtFixedRate]].
*/
@ -72,16 +121,29 @@ trait TimerScheduler[T] {
def startPeriodicTimer(key: Any, msg: T, interval: Duration): Unit
/**
* * Start a timer that will send `msg` once to the `self` actor after
* Start a timer that will send `msg` once to the `self` actor after
* the given `delay`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startSingleTimer(key: Any, msg: T, delay: Duration): Unit
/**
* Start a timer that will send `msg` once to the `self` actor after
* the given `delay`.
*
* When a new timer is started with the same message
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started. If you do not want this,
* you can start start them as individual timers by specifying distinct keys.
*/
def startSingleTimer(msg: T, delay: Duration): Unit =
startSingleTimer(msg, msg, delay)
/**
* Check if a timer with a given `key` is active.
*/

View file

@ -29,12 +29,32 @@ trait TimerScheduler[T] {
* the reciprocal of the specified `delay`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already be enqueued
* in the mailbox before the new timer was started.
*/
def startTimerWithFixedDelay(key: Any, msg: T, delay: FiniteDuration): Unit
/**
* Schedules a message to be sent repeatedly to the `self` actor with a
* fixed `delay` between messages.
*
* It will not compensate the delay between messages if scheduling is delayed
* longer than specified for some reason. The delay between sending of subsequent
* messages will always be (at least) the given `delay`.
*
* In the long run, the frequency of messages will generally be slightly lower than
* the reciprocal of the specified `delay`.
*
* When a new timer is started with the same message,
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started. If you do not want this,
* you can start start them as individual timers by specifying distinct keys.
*/
def startTimerWithFixedDelay(msg: T, delay: FiniteDuration): Unit =
startTimerWithFixedDelay(msg, msg, delay)
/**
* Schedules a message to be sent repeatedly to the `self` actor with a
* given frequency.
@ -56,12 +76,41 @@ trait TimerScheduler[T] {
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerAtFixedRate(key: Any, msg: T, interval: FiniteDuration): Unit
/**
* Schedules a message to be sent repeatedly to the `self` actor with a
* given frequency.
*
* It will compensate the delay for a subsequent message if the sending of previous
* message was delayed more than specified. In such cases, the actual message interval
* will differ from the interval passed to the method.
*
* If the execution is delayed longer than the `interval`, the subsequent message will
* be sent immediately after the prior one. This also has the consequence that after
* long garbage collection pauses or other reasons when the JVM was suspended all
* "missed" messages will be sent when the process wakes up again.
*
* In the long run, the frequency of messages will be exactly the reciprocal of the
* specified `interval`.
*
* Warning: `startTimerAtFixedRate` can result in bursts of scheduled messages after long
* garbage collection pauses, which may in worst case cause undesired load on the system.
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* When a new timer is started with the same message
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started. If you do not want this,
* you can start start them as individual timers by specifying distinct keys.
*/
def startTimerAtFixedRate(msg: T, interval: FiniteDuration): Unit =
startTimerAtFixedRate(msg, msg, interval)
/**
* Deprecated API: See [[TimerScheduler#startTimerWithFixedDelay]] or [[TimerScheduler#startTimerAtFixedRate]].
*/
@ -76,12 +125,25 @@ trait TimerScheduler[T] {
* the given `delay`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startSingleTimer(key: Any, msg: T, delay: FiniteDuration): Unit
/**
* Start a timer that will send `msg` once to the `self` actor after
* the given `delay`.
*
* If a new timer is started with the same message
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started. If you do not want this,
* you can start start them as individual timers by specifying distinct keys.
*/
def startSingleTimer(msg: T, delay: FiniteDuration): Unit =
startSingleTimer(msg, msg, delay)
/**
* Check if a timer with a given `key` is active.
*/

View file

@ -444,9 +444,9 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
* the reciprocal of the specified `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerWithFixedDelay(name: String, msg: Any, delay: java.time.Duration): Unit =
startTimerWithFixedDelay(name, msg, delay.asScala)
@ -472,9 +472,9 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerAtFixedRate(name: String, msg: Any, interval: java.time.Duration): Unit =
startTimerAtFixedRate(name, msg, interval.asScala)
@ -484,9 +484,9 @@ abstract class AbstractFSM[S, D] extends FSM[S, D] {
* the given `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startSingleTimer(name: String, msg: Any, delay: java.time.Duration): Unit =
startSingleTimer(name, msg, delay.asScala)

View file

@ -486,9 +486,9 @@ trait FSM[S, D] extends Actor with Listeners with ActorLogging {
* the reciprocal of the specified `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerWithFixedDelay(name: String, msg: Any, delay: FiniteDuration): Unit =
startTimer(name, msg, delay, FixedDelayMode)
@ -514,9 +514,9 @@ trait FSM[S, D] extends Actor with Listeners with ActorLogging {
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerAtFixedRate(name: String, msg: Any, interval: FiniteDuration): Unit =
startTimer(name, msg, interval, FixedRateMode)
@ -526,9 +526,9 @@ trait FSM[S, D] extends Actor with Listeners with ActorLogging {
* the given `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startSingleTimer(name: String, msg: Any, delay: FiniteDuration): Unit =
startTimer(name, msg, delay, SingleMode)

View file

@ -97,9 +97,9 @@ abstract class AbstractActorWithTimers extends AbstractActor with Timers {
* the reciprocal of the specified `delay`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerWithFixedDelay(key: Any, msg: Any, delay: FiniteDuration): Unit
@ -115,9 +115,9 @@ abstract class AbstractActorWithTimers extends AbstractActor with Timers {
* the reciprocal of the specified `delay`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
final def startTimerWithFixedDelay(key: Any, msg: Any, delay: java.time.Duration): Unit =
startTimerWithFixedDelay(key, msg, delay.asScala)
@ -143,9 +143,9 @@ abstract class AbstractActorWithTimers extends AbstractActor with Timers {
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerAtFixedRate(key: Any, msg: Any, interval: FiniteDuration): Unit
@ -170,9 +170,9 @@ abstract class AbstractActorWithTimers extends AbstractActor with Timers {
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
final def startTimerAtFixedRate(key: Any, msg: Any, interval: java.time.Duration): Unit =
startTimerAtFixedRate(key, msg, interval.asScala)
@ -201,9 +201,9 @@ abstract class AbstractActorWithTimers extends AbstractActor with Timers {
* the given `timeout`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startSingleTimer(key: Any, msg: Any, timeout: FiniteDuration): Unit
@ -212,9 +212,9 @@ abstract class AbstractActorWithTimers extends AbstractActor with Timers {
* the given `timeout`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
final def startSingleTimer(key: Any, msg: Any, timeout: java.time.Duration): Unit =
startSingleTimer(key, msg, timeout.asScala)

View file

@ -136,11 +136,11 @@ private[typed] object ClusterReceptionist extends ReceptionistBehaviorProvider {
// also periodic cleanup in case removal from ORMultiMap is skipped due to concurrent update,
// which is possible for OR CRDTs - done with an adapter to leverage the existing NodesRemoved message
timers.startTimerWithFixedDelay("remove-nodes", RemoveTick, setup.settings.pruningInterval)
timers.startTimerWithFixedDelay(RemoveTick, setup.settings.pruningInterval)
// default tomstone keepalive is 24h (based on prune-gossip-tombstones-after) and keeping the actorrefs
// around isn't very costly so don't prune often
timers.startTimerWithFixedDelay("prune-tombstones", PruneTombstonesTick, setup.keepTombstonesFor / 24)
timers.startTimerWithFixedDelay(PruneTombstonesTick, setup.keepTombstonesFor / 24)
behavior(setup, registry, TypedMultiMap.empty[AbstractServiceKey, SubscriptionsKV])
}

View file

@ -398,7 +398,7 @@ There are a few things worth noting here:
* To get access to the timers you start with `Behaviors.withTimers` that will pass a `TimerScheduler` instance to the function.
This can be used with any type of `Behavior`, including `receive`, `receiveMessage`, but also `setup` or any other behavior.
* Each timer has a key and if a new timer with the same key is started, the previous is cancelled and it's guaranteed that a message from the previous timer is not received, even though it might already be enqueued in the mailbox when the new timer is started.
* Each timer has a key and if a new timer with the same key is started, the previous is cancelled. It is guaranteed that a message from the previous timer is not received, even if it was already enqueued in the mailbox when the new timer was started.
* Both periodic and single message timers are supported.
* The `TimerScheduler` is mutable in itself, because it performs and manages the side effects of registering the scheduled tasks.
* The `TimerScheduler` is bound to the lifecycle of the actor that owns it and it's cancelled automatically when the actor is stopped.

View file

@ -78,7 +78,7 @@ public class DeviceGroupQuery extends AbstractBehavior<DeviceGroupQuery.Command>
this.requestId = requestId;
this.requester = requester;
timers.startSingleTimer(CollectionTimeout.class, CollectionTimeout.INSTANCE, timeout);
timers.startSingleTimer(CollectionTimeout.INSTANCE, timeout);
ActorRef<Device.RespondTemperature> respondTemperatureAdapter =
context.messageAdapter(Device.RespondTemperature.class, WrappedRespondTemperature::new);

View file

@ -205,7 +205,7 @@ object EventSourcedBehaviorSpec {
case IncrementLater =>
// purpose is to test signals
val delay = ctx.spawnAnonymous(Behaviors.withTimers[Tick.type] { timers =>
timers.startSingleTimer(Tick, Tick, 10.millis)
timers.startSingleTimer(Tick, 10.millis)
Behaviors.receive((_, msg) =>
msg match {
case Tick => Behaviors.stopped
@ -467,7 +467,7 @@ class EventSourcedBehaviorSpec
"handle scheduled message arriving before recovery completed " in {
val c = spawn(Behaviors.withTimers[Command] { timers =>
timers.startSingleTimer("tick", Increment, 1.millis)
timers.startSingleTimer(Increment, 1.millis)
Thread.sleep(30) // now it's probably already in the mailbox, and will be stashed
counter(nextPid)
})
@ -483,7 +483,7 @@ class EventSourcedBehaviorSpec
"handle scheduled message arriving after recovery completed " in {
val c = spawn(Behaviors.withTimers[Command] { timers =>
// probably arrives after recovery completed
timers.startSingleTimer("tick", Increment, 200.millis)
timers.startSingleTimer(Increment, 200.millis)
counter(nextPid)
})

View file

@ -145,7 +145,7 @@ object PersistentActorCompileOnlyTest {
})
Behaviors.withTimers((timers: TimerScheduler[Command]) => {
timers.startTimerWithFixedDelay("swing", MoodSwing, 10.seconds)
timers.startTimerWithFixedDelay(MoodSwing, 10.seconds)
b
})
}

View file

@ -213,9 +213,9 @@ trait PersistentFSMBase[S, D, E] extends Actor with Listeners with ActorLogging
* the reciprocal of the specified `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerWithFixedDelay(name: String, msg: Any, delay: FiniteDuration): Unit =
startTimer(name, msg, delay, FixedDelayMode)
@ -241,9 +241,9 @@ trait PersistentFSMBase[S, D, E] extends Actor with Listeners with ActorLogging
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerAtFixedRate(name: String, msg: Any, interval: FiniteDuration): Unit =
startTimer(name, msg, interval, FixedRateMode)
@ -253,9 +253,9 @@ trait PersistentFSMBase[S, D, E] extends Actor with Listeners with ActorLogging
* the given `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startSingleTimer(name: String, msg: Any, delay: FiniteDuration): Unit =
startTimer(name, msg, delay, SingleMode)
@ -1103,9 +1103,9 @@ abstract class AbstractPersistentFSMBase[S, D, E] extends PersistentFSMBase[S, D
* the reciprocal of the specified `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerWithFixedDelay(name: String, msg: Any, delay: java.time.Duration): Unit =
startTimerWithFixedDelay(name, msg, delay.asScala)
@ -1131,9 +1131,9 @@ abstract class AbstractPersistentFSMBase[S, D, E] extends PersistentFSMBase[S, D
* Therefore `startTimerWithFixedDelay` is often preferred.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startTimerAtFixedRate(name: String, msg: Any, interval: java.time.Duration): Unit =
startTimerAtFixedRate(name, msg, interval.asScala)
@ -1143,9 +1143,9 @@ abstract class AbstractPersistentFSMBase[S, D, E] extends PersistentFSMBase[S, D
* the given `delay`.
*
* Each timer has a `name` and if a new timer with same `name` is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
* the previous is cancelled. It is guaranteed that a message from the
* previous timer is not received, even if it was already enqueued
* in the mailbox when the new timer was started.
*/
def startSingleTimer(name: String, msg: Any, delay: java.time.Duration): Unit =
startSingleTimer(name, msg, delay.asScala)