Skip to content

Commit 3da9cb4

Browse files
chore: missing retry function with actor system provider (#32690)
--------- Co-authored-by: Johan Andrén <johan@markatta.com>
1 parent 3a21ccd commit 3da9cb4

File tree

6 files changed

+105
-29
lines changed

6 files changed

+105
-29
lines changed

akka-actor-tests/src/test/java/akka/pattern/RetrySettingsTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,26 @@
44

55
package akka.pattern;
66

7+
import static org.junit.Assert.assertEquals;
8+
9+
import akka.testkit.AkkaJUnitActorSystemResource;
10+
import akka.testkit.AkkaSpec;
711
import com.typesafe.config.ConfigFactory;
812
import java.time.Duration;
913
import java.util.Optional;
14+
import java.util.concurrent.CompletableFuture;
15+
import java.util.concurrent.CompletionStage;
16+
import java.util.concurrent.TimeUnit;
17+
import org.junit.ClassRule;
1018
import org.junit.Test;
1119
import org.scalatestplus.junit.JUnitSuite;
1220

1321
public class RetrySettingsTest extends JUnitSuite {
1422

23+
@ClassRule
24+
public static AkkaJUnitActorSystemResource actorSystemResource =
25+
new AkkaJUnitActorSystemResource("RetrySettingsTest", AkkaSpec.testConf());
26+
1527
@Test
1628
public void shouldCreateRetrySetting() {
1729
// mostly for testing compilation issues
@@ -23,4 +35,17 @@ public void shouldCreateRetrySetting() {
2335
RetrySettings.create(2).withJavaDelayFunction(retryNum -> Optional.of(Duration.ofSeconds(1)));
2436
RetrySettings.create(2).withJavaDecider(__ -> true);
2537
}
38+
39+
@Test
40+
public void retryCallableWithClassicSystem() throws Exception {
41+
42+
// make sure the overload is callable
43+
CompletionStage<String> result =
44+
Patterns.retry(
45+
() -> CompletableFuture.completedFuture("woho"),
46+
RetrySettings.create(2),
47+
actorSystemResource.getSystem());
48+
49+
assertEquals("woho", result.toCompletableFuture().get(3, TimeUnit.SECONDS));
50+
}
2651
}

akka-actor-tests/src/test/scala/akka/pattern/RetrySpec.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,12 @@ class RetrySpec extends AkkaSpec with RetrySupport {
173173
}
174174
}
175175

176+
"provide a retry settings based api" in {
177+
// just a successful try to cover API and implicit system provider
178+
val retried = retry(RetrySettings(5).withFixedDelay(40.millis)) { () =>
179+
Future.successful(5)
180+
}
181+
retried.futureValue should ===(5)
182+
}
183+
176184
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (C) 2025 Lightbend Inc. <https://www.lightbend.com>
3+
*/
4+
5+
package akka.pattern;
6+
7+
import static org.junit.Assert.assertEquals;
8+
9+
import akka.actor.testkit.typed.javadsl.TestKitJunitResource;
10+
import akka.testkit.AkkaSpec;
11+
import java.time.Duration;
12+
import java.util.concurrent.CompletableFuture;
13+
import java.util.concurrent.CompletionStage;
14+
import java.util.concurrent.TimeUnit;
15+
import org.junit.ClassRule;
16+
import org.junit.Test;
17+
import org.scalatestplus.junit.JUnitSuite;
18+
19+
public class RetryTest extends JUnitSuite {
20+
21+
@ClassRule
22+
public static final TestKitJunitResource testKit = new TestKitJunitResource(AkkaSpec.testConf());
23+
24+
@Test
25+
public void testRetryIsCallableWithTypedSystem() throws Exception {
26+
27+
// just a successful try to cover API and implicit system provider
28+
CompletionStage<Integer> retried =
29+
Patterns.retry(
30+
() -> CompletableFuture.completedFuture(5),
31+
RetrySettings.create(5).withFixedDelay(Duration.ofMillis(40)),
32+
testKit.system());
33+
34+
assertEquals(Integer.valueOf(5), retried.toCompletableFuture().get(3, TimeUnit.SECONDS));
35+
}
36+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (C) 2009-2025 Lightbend Inc. <https://www.lightbend.com>
3+
*/
4+
5+
package akka.pattern
6+
7+
import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit
8+
import org.scalatest.concurrent.Futures
9+
import org.scalatest.matchers.should.Matchers
10+
import org.scalatest.wordspec.AnyWordSpecLike
11+
12+
import scala.concurrent.Future
13+
import scala.concurrent.duration.DurationInt
14+
15+
class RetrySpec extends ScalaTestWithActorTestKit with AnyWordSpecLike with Matchers with Futures {
16+
17+
"The RetrySettings based retry api" should {
18+
19+
"work with typed actor system" in {
20+
21+
// just a successful try to cover API and implicit system provider
22+
val retried = retry(RetrySettings(5).withFixedDelay(40.millis)) { () =>
23+
Future.successful(5)
24+
}
25+
26+
retried.futureValue should ===(5)
27+
}
28+
}
29+
30+
}

akka-actor/src/main/scala/akka/pattern/Patterns.scala

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -735,26 +735,9 @@ object Patterns {
735735
attempt: Callable[CompletionStage[T]],
736736
retrySettings: RetrySettings,
737737
system: ClassicActorSystemProvider): CompletionStage[T] = {
738-
retry(attempt, retrySettings, system.classicSystem.scheduler, system.classicSystem.dispatcher)
739-
}
740-
741-
/**
742-
* Returns an internally retrying [[java.util.concurrent.CompletionStage]].
743-
* The first attempt will be made immediately, each subsequent attempt will be made based on the provided [[akka.pattern.RetrySettings]].
744-
* A scheduler (e.g. context.system().scheduler()) must be provided to delay retries.
745-
*
746-
* If attempts are exhausted, the returned CompletionStage is that of the last attempt.
747-
* Note that the attempt function will be invoked on the given execution context for subsequent tries and therefore
748-
* must be thread safe (not touch unsafe mutable state).
749-
*/
750-
def retry[T](
751-
attempt: Callable[CompletionStage[T]],
752-
retrySettings: RetrySettings,
753-
scheduler: Scheduler,
754-
context: ExecutionContext): CompletionStage[T] = {
755738
scalaRetry(retrySettings) { () =>
756739
attempt.call().asScala
757-
}(context, scheduler).asJava
740+
}(system).asJava
758741
}
759742

760743
/**

akka-actor/src/main/scala/akka/pattern/RetrySupport.scala

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package akka.pattern
66

7+
import akka.actor.ClassicActorSystemProvider
8+
79
import java.util.concurrent.ThreadLocalRandom
810
import scala.concurrent.{ ExecutionContext, Future }
911
import scala.concurrent.duration.{ Duration, FiniteDuration }
@@ -254,14 +256,6 @@ trait RetrySupport {
254256
* Given a function from Unit to Future, returns an internally retrying Future.
255257
* The first attempt will be made immediately, any subsequent attempt will be made based on provided [[RetrySettings]].
256258
*
257-
* A scheduler (eg context.system.scheduler) must be provided to delay each retry.
258-
* You could provide a function to generate the next delay duration after first attempt,
259-
* this function should never return `null`, otherwise an [[IllegalArgumentException]] will be thrown.
260-
*
261-
* If attempts are exhausted the returned future is simply the result of invoking attempt.
262-
* Note that the attempt function will be invoked on the given execution context for subsequent
263-
* tries and therefore must be thread safe (not touch unsafe mutable state).
264-
*
265259
* <b>Example usage:</b>
266260
*
267261
* // retry with backoff
@@ -273,14 +267,14 @@ trait RetrySupport {
273267
* }
274268
* }}}
275269
*/
276-
def retry[T](retrySettings: RetrySettings)(
277-
attempt: () => Future[T])(implicit ec: ExecutionContext, scheduler: Scheduler): Future[T] = {
270+
def retry[T](retrySettings: RetrySettings)(attempt: () => Future[T])(
271+
implicit system: ClassicActorSystemProvider): Future[T] = {
278272
RetrySupport.retry(
279273
attempt,
280274
retrySettings.maxRetries,
281275
retrySettings.delayFunction,
282276
attempted = 0,
283-
retrySettings.shouldRetry)
277+
retrySettings.shouldRetry)(system.classicSystem.dispatcher, system.classicSystem.scheduler)
284278
}
285279
}
286280

0 commit comments

Comments
 (0)