Clarify typed supervision when returning a new behavior (#25163)
This commit is contained in:
parent
ec23844db6
commit
c8f4a17025
3 changed files with 104 additions and 14 deletions
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package jdocs.akka.typed.supervision;
|
||||
|
||||
import akka.actor.typed.ActorRef;
|
||||
import akka.actor.typed.Behavior;
|
||||
import akka.actor.typed.SupervisorStrategy;
|
||||
import akka.actor.typed.javadsl.Behaviors;
|
||||
|
|
@ -12,6 +13,40 @@ import scala.concurrent.duration.FiniteDuration;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SupervisionCompileOnlyTest {
|
||||
//#wrap
|
||||
interface CounterMessage { }
|
||||
|
||||
public static final class Increase implements CounterMessage { }
|
||||
|
||||
public static final class Get implements CounterMessage {
|
||||
final ActorRef<Got> sender;
|
||||
|
||||
public Get(ActorRef<Got> sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Got {
|
||||
final int n;
|
||||
|
||||
public Got(int n) {
|
||||
this.n = n;
|
||||
}
|
||||
}
|
||||
|
||||
public static Behavior<CounterMessage> counter(int currentValue) {
|
||||
return Behaviors.receive(CounterMessage.class)
|
||||
.onMessage(Increase.class, (ctx, o) -> {
|
||||
return counter(currentValue + 1);
|
||||
})
|
||||
.onMessage(Get.class, (ctx, o) -> {
|
||||
o.sender.tell(new Got(currentValue));
|
||||
return Behaviors.same();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
//#wrap
|
||||
|
||||
public static Behavior<String> behavior = Behaviors.empty();
|
||||
|
||||
public void supervision() {
|
||||
|
|
@ -28,14 +63,19 @@ public class SupervisionCompileOnlyTest {
|
|||
//#restart-limit
|
||||
Behaviors.supervise(behavior)
|
||||
.onFailure(IllegalStateException.class, SupervisorStrategy.restartWithLimit(
|
||||
10, FiniteDuration.apply(10, TimeUnit.SECONDS)
|
||||
));
|
||||
10, FiniteDuration.apply(10, TimeUnit.SECONDS)
|
||||
));
|
||||
//#restart-limit
|
||||
|
||||
//#multiple
|
||||
Behaviors.supervise(Behaviors.supervise(behavior)
|
||||
.onFailure(IllegalStateException.class, SupervisorStrategy.restart()))
|
||||
.onFailure(IllegalArgumentException.class, SupervisorStrategy.stop());
|
||||
.onFailure(IllegalArgumentException.class, SupervisorStrategy.stop());
|
||||
//#multiple
|
||||
|
||||
|
||||
//#top-level
|
||||
Behaviors.supervise(counter(1));
|
||||
//#top-level
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
package docs.akka.typed.supervision
|
||||
|
||||
import akka.actor.typed.SupervisorStrategy
|
||||
import akka.actor.typed.ActorRef
|
||||
import akka.actor.typed.{ Behavior, SupervisorStrategy }
|
||||
import akka.actor.typed.scaladsl.Behaviors
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
object SupervisionCompileOnlyTest {
|
||||
object SupervisionCompileOnly {
|
||||
|
||||
val behavior = Behaviors.empty[String]
|
||||
|
||||
|
|
@ -34,4 +36,22 @@ object SupervisionCompileOnlyTest {
|
|||
.onFailure[IllegalStateException](SupervisorStrategy.restart))
|
||||
.onFailure[IllegalArgumentException](SupervisorStrategy.stop)
|
||||
//#multiple
|
||||
|
||||
//#wrap
|
||||
sealed trait Command
|
||||
case class Increment(nr: Int) extends Command
|
||||
case class GetCount(replyTo: ActorRef[Int]) extends Command
|
||||
|
||||
def counter(count: Int): Behavior[Command] = Behaviors.receiveMessage[Command] {
|
||||
case Increment(nr: Int) ⇒
|
||||
counter(count + nr)
|
||||
case GetCount(replyTo) ⇒
|
||||
replyTo ! count
|
||||
Behaviors.same
|
||||
}
|
||||
//#wrap
|
||||
|
||||
//#top-level
|
||||
Behaviors.supervise(counter(1))
|
||||
//#top-level
|
||||
}
|
||||
|
|
@ -1,17 +1,27 @@
|
|||
# Fault Tolerance
|
||||
|
||||
When an actor throws an unexpected exception, a failure, while processing a message or during initialization, the actor will by default be stopped. Note that there is an important distinction between failures and validation errors:
|
||||
When an actor throws an unexpected exception, a failure, while processing a message or during initialization, the actor
|
||||
will by default be stopped. Note that there is an important distinction between failures and validation errors:
|
||||
|
||||
A validation error means that the data of a command sent to an actor is not valid, this should rather be modelled as a part of the actor protocol than make the actor throw exceptions.
|
||||
A validation error means that the data of a command sent to an actor is not valid, this should rather be modelled as a
|
||||
part of the actor protocol than make the actor throw exceptions.
|
||||
|
||||
A failure is instead something unexpected or outside the control of the actor itself, for example a database connection that broke. Opposite to validation errors, it is seldom useful to model such as parts of the protocol as a sending actor very seldom can do anything useful about it.
|
||||
A failure is instead something unexpected or outside the control of the actor itself, for example a database connection
|
||||
that broke. Opposite to validation errors, it is seldom useful to model such as parts of the protocol as a sending actor
|
||||
very seldom can do anything useful about it.
|
||||
|
||||
For failures it is useful to apply the "let it crash" philosophy: instead of mixing fine grained recovery and correction of internal state that may have become partially invalid because of the failure with the business logic we move that responsibility somewhere else. For many cases the resolution can then be to "crash" the actor, and start a new one, with a fresh state that we know is valid.
|
||||
For failures it is useful to apply the "let it crash" philosophy: instead of mixing fine grained recovery and correction
|
||||
of internal state that may have become partially invalid because of the failure with the business logic we move that
|
||||
responsibility somewhere else. For many cases the resolution can then be to "crash" the actor, and start a new one,
|
||||
with a fresh state that we know is valid.
|
||||
|
||||
## Supervision
|
||||
|
||||
In Akka Typed this "somewhere else" is called supervision. Supervision allows you to declaratively describe what should happen when a certain type of exceptions are thrown inside an actor. To use supervision the actual Actor behavior is wrapped using `Behaviors.supervise`, for example to restart on `IllegalStateExceptions`:
|
||||
|
||||
In Akka Typed this "somewhere else" is called supervision. Supervision allows you to delaratively describe what should happen when a certain type of exceptions are thrown inside an actor. To use supervision the actual Actor behavior is wrapped using `Behaviors.supervise`, for example to restart on `IllegalStateExceptions`:
|
||||
|
||||
Scala
|
||||
: @@snip [SupervisionCompileOnlyTest.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnlyTest.scala) { #restart }
|
||||
: @@snip [SupervisionCompileOnly.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnly.scala) { #restart }
|
||||
|
||||
Java
|
||||
: @@snip [SupervisionCompileOnlyTest.java]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/supervision/SupervisionCompileOnlyTest.java) { #restart }
|
||||
|
|
@ -19,7 +29,7 @@ Java
|
|||
Or to resume, ignore the failure and process the next message, instead:
|
||||
|
||||
Scala
|
||||
: @@snip [SupervisionCompileOnlyTest.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnlyTest.scala) { #resume }
|
||||
: @@snip [SupervisionCompileOnly.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnly.scala) { #resume }
|
||||
|
||||
Java
|
||||
: @@snip [SupervisionCompileOnlyTest.java]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/supervision/SupervisionCompileOnlyTest.java) { #resume }
|
||||
|
|
@ -28,7 +38,7 @@ More complicated restart strategies can be used e.g. to restart no more than 10
|
|||
times in a 10 second period:
|
||||
|
||||
Scala
|
||||
: @@snip [SupervisionCompileOnlyTest.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnlyTest.scala) { #restart-limit }
|
||||
: @@snip [SupervisionCompileOnly.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnly.scala) { #restart-limit }
|
||||
|
||||
Java
|
||||
: @@snip [SupervisionCompileOnlyTest.java]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/supervision/SupervisionCompileOnlyTest.java) { #restart-limit }
|
||||
|
|
@ -37,13 +47,33 @@ To handle different exceptions with different strategies calls to `supervise`
|
|||
can be nested:
|
||||
|
||||
Scala
|
||||
: @@snip [SupervisionCompileOnlyTest.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnlyTest.scala) { #multiple }
|
||||
: @@snip [SupervisionCompileOnly.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnly.scala) { #multiple }
|
||||
|
||||
Java
|
||||
: @@snip [SupervisionCompileOnlyTest.java]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/supervision/SupervisionCompileOnlyTest.java) { #multiple }
|
||||
|
||||
For a full list of strategies see the public methods on `SupervisorStrategy`
|
||||
|
||||
### Wrapping behaviors
|
||||
|
||||
It is very common to store state by changing behavior e.g.
|
||||
|
||||
Scala
|
||||
: @@snip [SupervisionCompileOnly.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnly.scala) { #wrap }
|
||||
|
||||
Java
|
||||
: @@snip [SupervisionCompileOnlyTest.java]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/supervision/SupervisionCompileOnlyTest.java) { #wrap }
|
||||
|
||||
When doing this supervision only needs to be added to the top level:
|
||||
|
||||
Scala
|
||||
: @@snip [SupervisionCompileOnly.scala]($akka$/akka-actor-typed-tests/src/test/scala/docs/akka/typed/supervision/SupervisionCompileOnly.scala) { #top-level }
|
||||
|
||||
Java
|
||||
: @@snip [SupervisionCompileOnlyTest.java]($akka$/akka-actor-typed-tests/src/test/java/jdocs/akka/typed/supervision/SupervisionCompileOnlyTest.java) { #top-level }
|
||||
|
||||
Each returned behavior will be re-wrapped automatically with the supervisor.
|
||||
|
||||
|
||||
## Bubble failures up through the hierarchy
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue