You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pekko.apache.org by he...@apache.org on 2024/01/19 04:33:26 UTC

(incubator-pekko) branch 1.0.x updated: fix: reject zero and negative periodic tasks schedule (#887)

This is an automated email from the ASF dual-hosted git repository.

hepin pushed a commit to branch 1.0.x
in repository https://gitbox.apache.org/repos/asf/incubator-pekko.git


The following commit(s) were added to refs/heads/1.0.x by this push:
     new b6b9611169 fix: reject zero and negative periodic tasks schedule (#887)
b6b9611169 is described below

commit b6b96111691cf0b87f7e25864d1d857fe7c5a61f
Author: AndyChen <iR...@gmail.com>
AuthorDate: Thu Jan 18 19:47:13 2024 +0800

    fix: reject zero and negative periodic tasks schedule (#887)
    
    * fix: reject zero and negative periodic tasks schedule
    
    * fix: undo the symbol change
    
    * use different test name, redescribe the exception
    
    * abstract check function
    
    * remove the printlns change
    
    * reduce time units scale convert
---
 .../org/apache/pekko/actor/SchedulerSpec.scala     | 57 ++++++++++++++++++++++
 .../pekko/actor/LightArrayRevolverScheduler.scala  |  8 +++
 .../scala/org/apache/pekko/actor/Scheduler.scala   | 18 +++----
 3 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala b/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala
index fbd3176619..b245d963f3 100644
--- a/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala
+++ b/actor-tests/src/test/scala/org/apache/pekko/actor/SchedulerSpec.scala
@@ -661,6 +661,45 @@ class LightArrayRevolverSchedulerSpec extends PekkoSpec(SchedulerSpec.testConfRe
       }
     }
 
+    "using scheduleAtFixedRate" must {
+      "fixed rate reject periodic tasks scheduled with zero interval" taggedAs TimingTest in {
+        val zeroInterval = 0.seconds
+        import system.dispatcher
+        intercept[IllegalArgumentException] {
+          system.scheduler.scheduleAtFixedRate(100.millis, zeroInterval, testActor, "Not Allowed")
+        }
+        expectNoMessage(1.second)
+      }
+
+      "fixed rate reject periodic tasks scheduled with negative interval" taggedAs TimingTest in {
+        val negativeDelay = -1.seconds
+        import system.dispatcher
+        intercept[IllegalArgumentException] {
+          system.scheduler.scheduleAtFixedRate(100.millis, negativeDelay, testActor, "Not Allowed")
+        }
+        expectNoMessage(1.second)
+      }
+    }
+
+    "using scheduleWithFixedDelay" must {
+      "fixed delay reject periodic tasks scheduled with zero interval" taggedAs TimingTest in {
+        val zeroInterval = 0.seconds
+        import system.dispatcher
+        intercept[IllegalArgumentException] {
+          system.scheduler.scheduleWithFixedDelay(100.millis, zeroInterval, testActor, "Not Allowed")
+        }
+        expectNoMessage(1.second)
+      }
+
+      "fixed delay reject periodic tasks scheduled with negative interval" taggedAs TimingTest in {
+        val negativeDelay = -1.seconds
+        import system.dispatcher
+        intercept[IllegalArgumentException] {
+          system.scheduler.scheduleWithFixedDelay(100.millis, negativeDelay, testActor, "Not Allowed")
+        }
+        expectNoMessage(1.second)
+      }
+    }
     // same tests for fixedDelay and fixedRate
     List(new ScheduleWithFixedDelayAdapter, new ScheduleAtFixedRateAdapter).foreach { scheduleAdapter =>
       s"using $scheduleAdapter" must {
@@ -684,6 +723,24 @@ class LightArrayRevolverSchedulerSpec extends PekkoSpec(SchedulerSpec.testConfRe
           }
           expectNoMessage(1.second)
         }
+
+        "reject periodic tasks scheduled with zero interval" taggedAs TimingTest in {
+          val zeroInterval = 0.seconds
+          import system.dispatcher
+          intercept[IllegalArgumentException] {
+            scheduleAdapter.schedule(100.millis, zeroInterval, testActor, "Not Allowed")
+          }
+          expectNoMessage(1.second)
+        }
+
+        "reject periodic tasks scheduled with negative interval" taggedAs TimingTest in {
+          val negativeInterval = -1.seconds
+          import system.dispatcher
+          intercept[IllegalArgumentException] {
+            scheduleAdapter.schedule(100.millis, negativeInterval, testActor, "Not Allowed")
+          }
+          expectNoMessage(1.second)
+        }
       }
     }
 
diff --git a/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala b/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala
index 4b9cd82200..dcd3e4cc96 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/LightArrayRevolverScheduler.scala
@@ -104,12 +104,14 @@ class LightArrayRevolverScheduler(config: Config, log: LoggingAdapter, threadFac
 
   override def scheduleWithFixedDelay(initialDelay: FiniteDuration, delay: FiniteDuration)(runnable: Runnable)(
       implicit executor: ExecutionContext): Cancellable = {
+    checkPeriod(delay)
     checkMaxDelay(roundUp(delay).toNanos)
     super.scheduleWithFixedDelay(initialDelay, delay)(runnable)
   }
 
   override def schedule(initialDelay: FiniteDuration, delay: FiniteDuration, runnable: Runnable)(
       implicit executor: ExecutionContext): Cancellable = {
+    checkPeriod(delay)
     checkMaxDelay(roundUp(delay).toNanos)
     try new AtomicReference[Cancellable](InitialRepeatMarker) with Cancellable { self =>
         compareAndSet(
@@ -218,6 +220,12 @@ class LightArrayRevolverScheduler(config: Config, log: LoggingAdapter, threadFac
       task
     }
 
+  private def checkPeriod(delay: FiniteDuration): Unit =
+    if (delay.length <= 0)
+      throw new IllegalArgumentException(
+        s"Task scheduled with [${delay.toSeconds}] seconds delay, which means creating an infinite loop. " +
+        s"The expected delay must be greater than 0.")
+
   private def checkMaxDelay(delayNanos: Long): Unit =
     if (delayNanos / tickNanos > Int.MaxValue)
       // 1 second margin in the error message due to rounding
diff --git a/actor/src/main/scala/org/apache/pekko/actor/Scheduler.scala b/actor/src/main/scala/org/apache/pekko/actor/Scheduler.scala
index 41abe832e4..95e5832f49 100644
--- a/actor/src/main/scala/org/apache/pekko/actor/Scheduler.scala
+++ b/actor/src/main/scala/org/apache/pekko/actor/Scheduler.scala
@@ -75,7 +75,7 @@ trait Scheduler {
    * If the `Runnable` throws an exception the repeated scheduling is aborted,
    * i.e. the function will not be invoked any more.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `with Timers` should be preferred.
@@ -144,7 +144,7 @@ trait Scheduler {
    * If the `Runnable` throws an exception the repeated scheduling is aborted,
    * i.e. the function will not be invoked any more.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `AbstractActorWithTimers` should be preferred.
@@ -243,7 +243,7 @@ trait Scheduler {
    * If the `Runnable` throws an exception the repeated scheduling is aborted,
    * i.e. the function will not be invoked any more.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `with Timers` should be preferred.
@@ -279,7 +279,7 @@ trait Scheduler {
    * If the `Runnable` throws an exception the repeated scheduling is aborted,
    * i.e. the function will not be invoked any more.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `AbstractActorWithTimers` should be preferred.
@@ -443,7 +443,7 @@ trait Scheduler {
    * Scala API: Schedules a message to be sent once with a delay, i.e. a time period that has
    * to pass before the message is sent.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `with Timers` should be preferred.
@@ -461,7 +461,7 @@ trait Scheduler {
    * Java API: Schedules a message to be sent once with a delay, i.e. a time period that has
    * to pass before the message is sent.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `AbstractActorWithTimers` should be preferred.
@@ -480,7 +480,7 @@ trait Scheduler {
    * Scala API: Schedules a function to be run once with a delay, i.e. a time period that has
    * to pass before the function is run.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `with Timers` should be preferred.
@@ -494,7 +494,7 @@ trait Scheduler {
    * Scala API: Schedules a Runnable to be run once with a delay, i.e. a time period that
    * has to pass before the runnable is executed.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `with Timers` should be preferred.
@@ -505,7 +505,7 @@ trait Scheduler {
    * Java API: Schedules a Runnable to be run once with a delay, i.e. a time period that
    * has to pass before the runnable is executed.
    *
-   * @throws IllegalArgumentException if the given delays exceed the maximum
+   * @throws IllegalArgumentException if the given delays is zero, negative or exceed the maximum
    * reach (calculated as: `delay / tickNanos > Int.MaxValue`).
    *
    * Note: For scheduling within actors `AbstractActorWithTimers` should be preferred.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pekko.apache.org
For additional commands, e-mail: commits-help@pekko.apache.org