Adapts and improves documentation #26156

This commit is contained in:
Nicolas Vollmar 2019-01-18 20:44:47 +01:00
parent 9f3b62a367
commit 9233ff5a40
8 changed files with 106 additions and 12 deletions

View file

@ -15,7 +15,7 @@ import scala.concurrent.duration._
*
* Back-off supervisor that stops and starts a child actor when the child actor restarts.
* This back-off supervisor is created by using ``akka.pattern.BackoffSupervisor.props``
* with ``akka.pattern.Backoff.onFailure``.
* with ``akka.pattern.BackoffOpts.onFailure``.
*/
@InternalApi private class BackoffOnRestartSupervisor(
val childProps: Props,

View file

@ -15,7 +15,7 @@ import scala.concurrent.duration.FiniteDuration
*
* Back-off supervisor that stops and starts a child actor using a back-off algorithm when the child actor stops.
* This back-off supervisor is created by using `akka.pattern.BackoffSupervisor.props`
* with `Backoff.onStop`.
* with `BackoffOpts.onStop`.
*/
@InternalApi private[akka] class BackoffOnStopSupervisor(
val childProps: Props,

View file

@ -333,7 +333,7 @@ private final case class BackoffOnStopOptionsImpl[T](
finalStopMessage: Option[Any Boolean] = None
) extends BackoffOnStopOptions {
val backoffReset = reset.getOrElse(AutoReset(minBackoff))
private val backoffReset = reset.getOrElse(AutoReset(minBackoff))
def withAutoReset(resetBackoff: FiniteDuration) = copy(reset = Some(AutoReset(resetBackoff)))
def withManualReset = copy(reset = Some(ManualReset))
@ -343,7 +343,7 @@ private final case class BackoffOnStopOptionsImpl[T](
def withMaxNrOfRetries(maxNrOfRetries: Int) = copy(supervisorStrategy = supervisorStrategy.withMaxNrOfRetries(maxNrOfRetries))
def withFinalStopMessage(action: Any Boolean) = copy(finalStopMessage = Some(action))
def props = {
def props: Props = {
require(minBackoff > Duration.Zero, "minBackoff must be > 0")
require(maxBackoff >= minBackoff, "maxBackoff must be >= minBackoff")
require(0.0 <= randomFactor && randomFactor <= 1.0, "randomFactor must be between 0.0 and 1.0")
@ -368,7 +368,7 @@ private final case class BackoffOnFailureOptionsImpl[T](
replyWhileStopped: Option[Any] = None
) extends BackoffOnFailureOptions {
val backoffReset = reset.getOrElse(AutoReset(minBackoff))
private val backoffReset = reset.getOrElse(AutoReset(minBackoff))
def withAutoReset(resetBackoff: FiniteDuration) = copy(reset = Some(AutoReset(resetBackoff)))
def withManualReset = copy(reset = Some(ManualReset))
@ -377,7 +377,7 @@ private final case class BackoffOnFailureOptionsImpl[T](
def withReplyWhileStopped(replyWhileStopped: Any) = copy(replyWhileStopped = Some(replyWhileStopped))
def withMaxNrOfRetries(maxNrOfRetries: Int) = copy(supervisorStrategy = supervisorStrategy.withMaxNrOfRetries(maxNrOfRetries))
def props = {
def props: Props = {
require(minBackoff > Duration.Zero, "minBackoff must be > 0")
require(maxBackoff >= minBackoff, "maxBackoff must be >= minBackoff")
require(0.0 <= randomFactor && randomFactor <= 1.0, "randomFactor must be between 0.0 and 1.0")

View file

@ -7,7 +7,7 @@ package akka.cluster.sharding
import akka.actor.{ Actor, ActorLogging, ActorRef, PoisonPill, Props }
import akka.cluster.Cluster
import akka.cluster.sharding.ShardRegion.Passivate
import akka.pattern.{ Backoff, BackoffSupervisor }
import akka.pattern.{ Backoff, BackoffOpts, BackoffSupervisor }
import akka.testkit.{ AkkaSpec, ImplicitSender }
import com.typesafe.config.ConfigFactory
@ -64,7 +64,7 @@ class SupervisionSpec extends AkkaSpec(SupervisionSpec.config) with ImplicitSend
import SupervisionSpec._
"Supervision for a sharded actor" must {
"Supervision for a sharded actor (deprecated)" must {
"allow passivation" in {
@ -99,4 +99,38 @@ class SupervisionSpec extends AkkaSpec(SupervisionSpec.config) with ImplicitSend
}
}
"Supervision for a sharded actor" must {
"allow passivation" in {
val supervisedProps = BackoffSupervisor.props(BackoffOpts.onStop(
Props(new PassivatingActor()),
childName = "child",
minBackoff = 1.seconds,
maxBackoff = 30.seconds,
randomFactor = 0.2
).withFinalStopMessage(_ == StopMessage))
Cluster(system).join(Cluster(system).selfAddress)
val region = ClusterSharding(system).start(
"passy",
supervisedProps,
ClusterShardingSettings(system),
idExtractor,
shardResolver
)
region ! Msg(10, "hello")
val response = expectMsgType[Response](5.seconds)
watch(response.self)
region ! Msg(10, "passivate")
expectTerminated(response.self)
// This would fail before as sharded actor would be stuck passivating
region ! Msg(10, "hello")
expectMsgType[Response](20.seconds)
}
}
}

View file

@ -413,6 +413,8 @@ Java
Note that stopped entities will be started again when a new message is targeted to the entity.
If 'on stop' backoff supervision strategy is used, a final termination message must be set and used for passivation, see #ref:[Supervision](general/supervision.md#Sharding)
## Graceful Shutdown
You can send the @scala[`ShardRegion.GracefulShutdown`] @java[`ShardRegion.gracefulShutdownInstance`] message

View file

@ -207,6 +207,25 @@ to recover before the persistent actor is started.
> <a id="1" href="#^1">[1]</a> A failure can be indicated in two different ways; by an actor stopping or crashing.
#### Supervision strategies
There are two basic supervision strategies available for backoff:
* 'On failure': The supervisor will restart the supervised actor once it crashes, but terminate if the actor stops normaly (e.g. through `context.stop`)
* 'On stop': The supervisor will restart the supervised actor if it terminates in any way (consider this for `PersistentActor` since they stop on persistence failures instead of crashing)
#### Sharding
If the 'on stop' strategy is used for sharded actors a final termination message should be configured and used to terminate the actor on passivation. Otherwise the supervisor will just restart the actor again.
The termination message is configured with:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-sharded }
And must be used for passivation:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-sharded-passivation }
#### Simple backoff
The following Scala snippet shows how to create a backoff supervisor which will start the given echo actor after it has stopped
because of a failure, in increasing intervals of 3, 6, 12, 24 and finally 30 seconds:
@ -239,7 +258,21 @@ The above is equivalent to this Java code:
@@snip [BackoffSupervisorDocTest.java](/akka-docs/src/test/java/jdocs/pattern/BackoffSupervisorDocTest.java) { #backoff-fail }
The `akka.pattern.BackoffOptions` can be used to customize the behavior of the back-off supervisor actor, below are some examples:
#### Customization
The `akka.pattern.BackoffOnFailureOptions` and `akka.pattern.BackoffOnRestartOptions` can be used to customize the behavior of the back-off supervisor actor.
Options are:
* `withAutoReset`: The backoff is reset if no failure/stop occurs within the duration. This is the default behaviour with `minBackoff` as default value
* `withManualReset`: The child must send `BackoffSupervisor.Reset` to its backoff supervisor (parent)
* `withSupervisionStrategy`: Sets a custom `OneForOneStrategy` (as each backoff supervisor only has one child). The default strategy uses the `akka.actor.SupervisorStrategy.defaultDecider` which restarts on exceptions.
* `withDefaultStoppingStrategy`: Sets a `OneForOneStrategy` with the stopping decider that stops the child on all exceptions.
* `withMaxNrOfRetries`: Sets the maximum number of retries until the supervisor will give up (`-1` is default which means no limit of retries). Note: This is set on the supervision strategy, so setting a different strategy resets the `maxNrOfRetries`.
* `withReplyWhileStopped`: By default all messages received while the child is stopped are forwarded to dead letters. With this set, the supervisor will reply to the sender instead.
Only available on `BackoffOnStopOptions`:
* `withFinalStopMessage`: Allows to define a predicate to decide on finally stopping the child (and supervisor). Used for passivate sharded actors - see above.
Some examples:
@@snip [BackoffSupervisorDocSpec.scala](/akka-docs/src/test/scala/docs/pattern/BackoffSupervisorDocSpec.scala) { #backoff-custom-stop }

View file

@ -6,6 +6,7 @@ package jdocs.pattern;
import akka.actor.*;
import akka.pattern.Backoff;
import akka.pattern.BackoffOpts;
import akka.pattern.BackoffSupervisor;
import akka.testkit.TestActors.EchoActor;
// #backoff-imports
@ -20,7 +21,7 @@ public class BackoffSupervisorDocTest {
final Props supervisorProps =
BackoffSupervisor.props(
Backoff.onStop(
BackoffOpts.onStop(
childProps,
"myEcho",
Duration.ofSeconds(3),
@ -37,7 +38,7 @@ public class BackoffSupervisorDocTest {
final Props supervisorProps =
BackoffSupervisor.props(
Backoff.onFailure(
BackoffOpts.onFailure(
childProps,
"myEcho",
Duration.ofSeconds(3),

View file

@ -4,7 +4,8 @@
package docs.pattern
import akka.actor.{ ActorSystem, OneForOneStrategy, Props, SupervisorStrategy }
import akka.actor.{ ActorContext, ActorSystem, OneForOneStrategy, Props, SupervisorStrategy }
import akka.cluster.sharding.ShardRegion.Passivate
import akka.pattern.{ BackoffOpts, BackoffSupervisor }
import akka.testkit.TestActors.EchoActor
@ -99,4 +100,27 @@ class BackoffSupervisorDocSpec {
case class MyException(msg: String) extends Exception(msg)
case object StopMessage
class BackoffSupervisorDocSpecExampleSharding {
val system: ActorSystem = ???
val context: ActorContext = ???
import scala.concurrent.duration._
val childProps = Props(classOf[EchoActor])
//#backoff-sharded
val supervisor = BackoffSupervisor.props(BackoffOpts.onStop(
childProps,
childName = "myEcho",
minBackoff = 3.seconds,
maxBackoff = 30.seconds,
randomFactor = 0.2
).withFinalStopMessage(_ == StopMessage))
//#backoff-sharded
//#backoff-sharded-passivation
context.parent ! Passivate(StopMessage)
//#backoff-sharded-passivation
}
}