Simplify backoff supervision API #26156
This commit is contained in:
commit
c01e6b6d73
15 changed files with 1186 additions and 628 deletions
|
|
@ -4,3 +4,12 @@ ProblemFilters.exclude[DirectMissingMethodProblem]("akka.pattern.AskableActorRef
|
|||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.util.ccompat.package.fromCanBuildFrom")
|
||||
# Add optional field to ApiMayChange annotation #26409
|
||||
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.annotation.ApiMayChange.issue")
|
||||
|
||||
# Simplify backoff supervision API #19016
|
||||
ProblemFilters.exclude[MissingClassProblem]("akka.pattern.BackoffOnRestartSupervisor")
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.pattern.internal.BackoffOnRestartSupervisor.replyWhileStopped")
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.pattern.internal.BackoffOnRestartSupervisor.finalStopMessage")
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.pattern.internal.BackoffOnRestartSupervisor.this")
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.pattern.HandleBackoff.replyWhileStopped")
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.pattern.HandleBackoff.finalStopMessage")
|
||||
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.pattern.HandleBackoff.handleMessageToChild")
|
||||
|
|
|
|||
611
akka-actor/src/main/scala/akka/pattern/Backoff.scala
Normal file
611
akka-actor/src/main/scala/akka/pattern/Backoff.scala
Normal file
|
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2019 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.pattern
|
||||
|
||||
import akka.actor.{ OneForOneStrategy, Props, SupervisorStrategy }
|
||||
import akka.annotation.DoNotInherit
|
||||
import akka.pattern.internal.{ BackoffOnRestartSupervisor, BackoffOnStopSupervisor }
|
||||
import akka.util.JavaDurationConverters._
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
|
||||
/**
|
||||
* @deprecated This API is superseded by the [[BackoffOpts]] object.
|
||||
*/
|
||||
@Deprecated
|
||||
@deprecated("Use new API from BackoffOpts object instead", since = "2.5.22")
|
||||
object Backoff {
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
*
|
||||
* This explicit supervisor behaves similarly to the normal implicit supervision where
|
||||
* if an actor throws an exception, the decider on the supervisor will decide when to
|
||||
* `Stop`, `Restart`, `Escalate`, `Resume` the child actor.
|
||||
*
|
||||
* When the `Restart` directive is specified, the supervisor will delay the restart
|
||||
* using an exponential back off strategy (bounded by minBackoff and maxBackoff).
|
||||
*
|
||||
* This supervisor is intended to be transparent to both the child actor and external actors.
|
||||
* Where external actors can send messages to the supervisor as if it was the child and the
|
||||
* messages will be forwarded. And when the child is `Terminated`, the supervisor is also
|
||||
* `Terminated`.
|
||||
* Transparent to the child means that the child does not have to be aware that it is being
|
||||
* supervised specifically by this actor. Just like it does
|
||||
* not need to know when it is being supervised by the usual implicit supervisors.
|
||||
* The only caveat is that the `ActorRef` of the child is not stable, so any user storing the
|
||||
* `sender()` `ActorRef` from the child response may eventually not be able to communicate with
|
||||
* the stored `ActorRef`. In general all messages to the child should be directed through this actor.
|
||||
*
|
||||
* An example of where this supervisor might be used is when you may have an actor that is
|
||||
* responsible for continuously polling on a server for some resource that sometimes may be down.
|
||||
* Instead of hammering the server continuously when the resource is unavailable, the actor will
|
||||
* be restarted with an exponentially increasing back off until the resource is available again.
|
||||
*
|
||||
* '''***
|
||||
* This supervisor should not be used with `Akka Persistence` child actors.
|
||||
* `Akka Persistence` actors shutdown unconditionally on `persistFailure()`s rather
|
||||
* than throw an exception on a failure like normal actors.
|
||||
* [[#onStop]] should be used instead for cases where the child actor
|
||||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*
|
||||
*/
|
||||
@deprecated("Use BackoffOpts.onFailure instead", "2.5.22")
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
BackoffOptionsImpl(RestartImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor).withMaxNrOfRetries(maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
*
|
||||
* This explicit supervisor behaves similarly to the normal implicit supervision where
|
||||
* if an actor throws an exception, the decider on the supervisor will decide when to
|
||||
* `Stop`, `Restart`, `Escalate`, `Resume` the child actor.
|
||||
*
|
||||
* When the `Restart` directive is specified, the supervisor will delay the restart
|
||||
* using an exponential back off strategy (bounded by minBackoff and maxBackoff).
|
||||
*
|
||||
* This supervisor is intended to be transparent to both the child actor and external actors.
|
||||
* Where external actors can send messages to the supervisor as if it was the child and the
|
||||
* messages will be forwarded. And when the child is `Terminated`, the supervisor is also
|
||||
* `Terminated`.
|
||||
* Transparent to the child means that the child does not have to be aware that it is being
|
||||
* supervised specifically by this actor. Just like it does
|
||||
* not need to know when it is being supervised by the usual implicit supervisors.
|
||||
* The only caveat is that the `ActorRef` of the child is not stable, so any user storing the
|
||||
* `sender()` `ActorRef` from the child response may eventually not be able to communicate with
|
||||
* the stored `ActorRef`. In general all messages to the child should be directed through this actor.
|
||||
*
|
||||
* An example of where this supervisor might be used is when you may have an actor that is
|
||||
* responsible for continuously polling on a server for some resource that sometimes may be down.
|
||||
* Instead of hammering the server continuously when the resource is unavailable, the actor will
|
||||
* be restarted with an exponentially increasing back off until the resource is available again.
|
||||
*
|
||||
* '''***
|
||||
* This supervisor should not be used with `Akka Persistence` child actors.
|
||||
* `Akka Persistence` actors shutdown unconditionally on `persistFailure()`s rather
|
||||
* than throw an exception on a failure like normal actors.
|
||||
* [[#onStop]] should be used instead for cases where the child actor
|
||||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@deprecated("Use BackoffOpts.onFailure instead", "2.5.22")
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
BackoffOptionsImpl(RestartImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
*
|
||||
* This explicit supervisor behaves similarly to the normal implicit supervision where
|
||||
* if an actor throws an exception, the decider on the supervisor will decide when to
|
||||
* `Stop`, `Restart`, `Escalate`, `Resume` the child actor.
|
||||
*
|
||||
* When the `Restart` directive is specified, the supervisor will delay the restart
|
||||
* using an exponential back off strategy (bounded by minBackoff and maxBackoff).
|
||||
*
|
||||
* This supervisor is intended to be transparent to both the child actor and external actors.
|
||||
* Where external actors can send messages to the supervisor as if it was the child and the
|
||||
* messages will be forwarded. And when the child is `Terminated`, the supervisor is also
|
||||
* `Terminated`.
|
||||
* Transparent to the child means that the child does not have to be aware that it is being
|
||||
* supervised specifically by this actor. Just like it does
|
||||
* not need to know when it is being supervised by the usual implicit supervisors.
|
||||
* The only caveat is that the `ActorRef` of the child is not stable, so any user storing the
|
||||
* `sender()` `ActorRef` from the child response may eventually not be able to communicate with
|
||||
* the stored `ActorRef`. In general all messages to the child should be directed through this actor.
|
||||
*
|
||||
* An example of where this supervisor might be used is when you may have an actor that is
|
||||
* responsible for continuously polling on a server for some resource that sometimes may be down.
|
||||
* Instead of hammering the server continuously when the resource is unavailable, the actor will
|
||||
* be restarted with an exponentially increasing back off until the resource is available again.
|
||||
*
|
||||
* '''***
|
||||
* This supervisor should not be used with `Akka Persistence` child actors.
|
||||
* `Akka Persistence` actors shutdown unconditionally on `persistFailure()`s rather
|
||||
* than throw an exception on a failure like normal actors.
|
||||
* [[#onStop]] should be used instead for cases where the child actor
|
||||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*/
|
||||
@Deprecated
|
||||
@deprecated("Use BackoffOpts.onFailure instead", "2.5.22")
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
onFailure(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
*
|
||||
* This explicit supervisor behaves similarly to the normal implicit supervision where
|
||||
* if an actor throws an exception, the decider on the supervisor will decide when to
|
||||
* `Stop`, `Restart`, `Escalate`, `Resume` the child actor.
|
||||
*
|
||||
* When the `Restart` directive is specified, the supervisor will delay the restart
|
||||
* using an exponential back off strategy (bounded by minBackoff and maxBackoff).
|
||||
*
|
||||
* This supervisor is intended to be transparent to both the child actor and external actors.
|
||||
* Where external actors can send messages to the supervisor as if it was the child and the
|
||||
* messages will be forwarded. And when the child is `Terminated`, the supervisor is also
|
||||
* `Terminated`.
|
||||
* Transparent to the child means that the child does not have to be aware that it is being
|
||||
* supervised specifically by this actor. Just like it does
|
||||
* not need to know when it is being supervised by the usual implicit supervisors.
|
||||
* The only caveat is that the `ActorRef` of the child is not stable, so any user storing the
|
||||
* `sender()` `ActorRef` from the child response may eventually not be able to communicate with
|
||||
* the stored `ActorRef`. In general all messages to the child should be directed through this actor.
|
||||
*
|
||||
* An example of where this supervisor might be used is when you may have an actor that is
|
||||
* responsible for continuously polling on a server for some resource that sometimes may be down.
|
||||
* Instead of hammering the server continuously when the resource is unavailable, the actor will
|
||||
* be restarted with an exponentially increasing back off until the resource is available again.
|
||||
*
|
||||
* '''***
|
||||
* This supervisor should not be used with `Akka Persistence` child actors.
|
||||
* `Akka Persistence` actors shutdown unconditionally on `persistFailure()`s rather
|
||||
* than throw an exception on a failure like normal actors.
|
||||
* [[#onStop]] should be used instead for cases where the child actor
|
||||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@Deprecated
|
||||
@deprecated("Use the overloaded one which accepts maxNrOfRetries instead.", "2.5.17")
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
onFailure(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, -1)
|
||||
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
*
|
||||
* This actor can be used to supervise a child actor and start it again
|
||||
* after a back-off duration if the child actor is stopped.
|
||||
*
|
||||
* This is useful in situations where the re-start of the child actor should be
|
||||
* delayed e.g. in order to give an external resource time to recover before the
|
||||
* child actor tries contacting it again (after being restarted).
|
||||
*
|
||||
* Specifically this pattern is useful for persistent actors,
|
||||
* which are stopped in case of persistence failures.
|
||||
* Just restarting them immediately would probably fail again (since the data
|
||||
* store is probably unavailable). It is better to try again after a delay.
|
||||
*
|
||||
* It supports exponential back-off between the given `minBackoff` and
|
||||
* `maxBackoff` durations. For example, if `minBackoff` is 3 seconds and
|
||||
* `maxBackoff` 30 seconds the start attempts will be delayed with
|
||||
* 3, 6, 12, 24, 30, 30 seconds. The exponential back-off counter is reset
|
||||
* if the actor is not terminated within the `minBackoff` duration.
|
||||
*
|
||||
* In addition to the calculated exponential back-off an additional
|
||||
* random delay based the given `randomFactor` is added, e.g. 0.2 adds up to 20%
|
||||
* delay. The reason for adding a random delay is to avoid that all failing
|
||||
* actors hit the backend resource at the same time.
|
||||
*
|
||||
* You can retrieve the current child `ActorRef` by sending `BackoffSupervisor.GetCurrentChild`
|
||||
* message to this actor and it will reply with [[akka.pattern.BackoffSupervisor.CurrentChild]]
|
||||
* containing the `ActorRef` of the current child, if any.
|
||||
*
|
||||
* The `BackoffSupervisor`delegates all messages from the child to the parent of the
|
||||
* `BackoffSupervisor`, with the supervisor as sender.
|
||||
*
|
||||
* The `BackoffSupervisor` forwards all other messages to the child, if it is currently running.
|
||||
*
|
||||
* The child can stop itself and send a [[akka.actor.PoisonPill]] to the parent supervisor
|
||||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*/
|
||||
@deprecated("Use BackoffOpts.onStop instead", "2.5.22")
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
BackoffOptionsImpl(StopImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor).withMaxNrOfRetries(maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
*
|
||||
* This actor can be used to supervise a child actor and start it again
|
||||
* after a back-off duration if the child actor is stopped.
|
||||
*
|
||||
* This is useful in situations where the re-start of the child actor should be
|
||||
* delayed e.g. in order to give an external resource time to recover before the
|
||||
* child actor tries contacting it again (after being restarted).
|
||||
*
|
||||
* Specifically this pattern is useful for persistent actors,
|
||||
* which are stopped in case of persistence failures.
|
||||
* Just restarting them immediately would probably fail again (since the data
|
||||
* store is probably unavailable). It is better to try again after a delay.
|
||||
*
|
||||
* It supports exponential back-off between the given `minBackoff` and
|
||||
* `maxBackoff` durations. For example, if `minBackoff` is 3 seconds and
|
||||
* `maxBackoff` 30 seconds the start attempts will be delayed with
|
||||
* 3, 6, 12, 24, 30, 30 seconds. The exponential back-off counter is reset
|
||||
* if the actor is not terminated within the `minBackoff` duration.
|
||||
*
|
||||
* In addition to the calculated exponential back-off an additional
|
||||
* random delay based the given `randomFactor` is added, e.g. 0.2 adds up to 20%
|
||||
* delay. The reason for adding a random delay is to avoid that all failing
|
||||
* actors hit the backend resource at the same time.
|
||||
*
|
||||
* You can retrieve the current child `ActorRef` by sending `BackoffSupervisor.GetCurrentChild`
|
||||
* message to this actor and it will reply with [[akka.pattern.BackoffSupervisor.CurrentChild]]
|
||||
* containing the `ActorRef` of the current child, if any.
|
||||
*
|
||||
* The `BackoffSupervisor`delegates all messages from the child to the parent of the
|
||||
* `BackoffSupervisor`, with the supervisor as sender.
|
||||
*
|
||||
* The `BackoffSupervisor` forwards all other messages to the child, if it is currently running.
|
||||
*
|
||||
* The child can stop itself and send a [[akka.actor.PoisonPill]] to the parent supervisor
|
||||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@deprecated("Use BackoffOpts.onStop instead", "2.5.22")
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
BackoffOptionsImpl(StopImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
*
|
||||
* This actor can be used to supervise a child actor and start it again
|
||||
* after a back-off duration if the child actor is stopped.
|
||||
*
|
||||
* This is useful in situations where the re-start of the child actor should be
|
||||
* delayed e.g. in order to give an external resource time to recover before the
|
||||
* child actor tries contacting it again (after being restarted).
|
||||
*
|
||||
* Specifically this pattern is useful for persistent actors,
|
||||
* which are stopped in case of persistence failures.
|
||||
* Just restarting them immediately would probably fail again (since the data
|
||||
* store is probably unavailable). It is better to try again after a delay.
|
||||
*
|
||||
* It supports exponential back-off between the given `minBackoff` and
|
||||
* `maxBackoff` durations. For example, if `minBackoff` is 3 seconds and
|
||||
* `maxBackoff` 30 seconds the start attempts will be delayed with
|
||||
* 3, 6, 12, 24, 30, 30 seconds. The exponential back-off counter is reset
|
||||
* if the actor is not terminated within the `minBackoff` duration.
|
||||
*
|
||||
* In addition to the calculated exponential back-off an additional
|
||||
* random delay based the given `randomFactor` is added, e.g. 0.2 adds up to 20%
|
||||
* delay. The reason for adding a random delay is to avoid that all failing
|
||||
* actors hit the backend resource at the same time.
|
||||
*
|
||||
* You can retrieve the current child `ActorRef` by sending `BackoffSupervisor.GetCurrentChild`
|
||||
* message to this actor and it will reply with [[akka.pattern.BackoffSupervisor.CurrentChild]]
|
||||
* containing the `ActorRef` of the current child, if any.
|
||||
*
|
||||
* The `BackoffSupervisor`delegates all messages from the child to the parent of the
|
||||
* `BackoffSupervisor`, with the supervisor as sender.
|
||||
*
|
||||
* The `BackoffSupervisor` forwards all other messages to the child, if it is currently running.
|
||||
*
|
||||
* The child can stop itself and send a [[akka.actor.PoisonPill]] to the parent supervisor
|
||||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*/
|
||||
@Deprecated
|
||||
@deprecated("Use BackoffOpts.onStop instead", "2.5.22")
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
onStop(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
*
|
||||
* This actor can be used to supervise a child actor and start it again
|
||||
* after a back-off duration if the child actor is stopped.
|
||||
*
|
||||
* This is useful in situations where the re-start of the child actor should be
|
||||
* delayed e.g. in order to give an external resource time to recover before the
|
||||
* child actor tries contacting it again (after being restarted).
|
||||
*
|
||||
* Specifically this pattern is useful for persistent actors,
|
||||
* which are stopped in case of persistence failures.
|
||||
* Just restarting them immediately would probably fail again (since the data
|
||||
* store is probably unavailable). It is better to try again after a delay.
|
||||
*
|
||||
* It supports exponential back-off between the given `minBackoff` and
|
||||
* `maxBackoff` durations. For example, if `minBackoff` is 3 seconds and
|
||||
* `maxBackoff` 30 seconds the start attempts will be delayed with
|
||||
* 3, 6, 12, 24, 30, 30 seconds. The exponential back-off counter is reset
|
||||
* if the actor is not terminated within the `minBackoff` duration.
|
||||
*
|
||||
* In addition to the calculated exponential back-off an additional
|
||||
* random delay based the given `randomFactor` is added, e.g. 0.2 adds up to 20%
|
||||
* delay. The reason for adding a random delay is to avoid that all failing
|
||||
* actors hit the backend resource at the same time.
|
||||
*
|
||||
* You can retrieve the current child `ActorRef` by sending `BackoffSupervisor.GetCurrentChild`
|
||||
* message to this actor and it will reply with [[akka.pattern.BackoffSupervisor.CurrentChild]]
|
||||
* containing the `ActorRef` of the current child, if any.
|
||||
*
|
||||
* The `BackoffSupervisor`delegates all messages from the child to the parent of the
|
||||
* `BackoffSupervisor`, with the supervisor as sender.
|
||||
*
|
||||
* The `BackoffSupervisor` forwards all other messages to the child, if it is currently running.
|
||||
*
|
||||
* The child can stop itself and send a [[akka.actor.PoisonPill]] to the parent supervisor
|
||||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@Deprecated
|
||||
@deprecated("Use the overloaded one which accepts maxNrOfRetries instead.", "2.5.17")
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
onStop(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a back-off supervisor actor. Start with `Backoff.onStop` or `Backoff.onFailure`.
|
||||
* BackoffOptions is immutable, so be sure to chain methods like:
|
||||
* {{{
|
||||
* val options = Backoff.onFailure(childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
* .withManualReset
|
||||
* context.actorOf(BackoffSupervisor.props(options), name)
|
||||
* }}}
|
||||
*/
|
||||
@DoNotInherit
|
||||
@Deprecated
|
||||
@deprecated("Use new API from BackoffOpts object instead", since = "2.5.22")
|
||||
trait BackoffOptions {
|
||||
|
||||
/**
|
||||
* @see [[ExtendedBackoffOptions.withAutoReset()]]
|
||||
*/
|
||||
def withAutoReset(resetBackoff: FiniteDuration): BackoffOptions
|
||||
|
||||
/**
|
||||
* @see [[ExtendedBackoffOptions.withManualReset()]]
|
||||
*/
|
||||
def withManualReset: BackoffOptions
|
||||
|
||||
/**
|
||||
* @see [[ExtendedBackoffOptions.withSupervisorStrategy()]]
|
||||
*/
|
||||
def withSupervisorStrategy(supervisorStrategy: OneForOneStrategy): BackoffOptions
|
||||
|
||||
/**
|
||||
* @see [[ExtendedBackoffOptions.withDefaultStoppingStrategy()]]
|
||||
*/
|
||||
def withDefaultStoppingStrategy: BackoffOptions
|
||||
|
||||
/**
|
||||
* @see [[ExtendedBackoffOptions.withMaxNrOfRetries()]]
|
||||
*/
|
||||
def withMaxNrOfRetries(maxNrOfRetries: Int): BackoffOptions
|
||||
|
||||
/**
|
||||
* @see [[ExtendedBackoffOptions.withReplyWhileStopped()]]
|
||||
*/
|
||||
def withReplyWhileStopped(replyWhileStopped: Any): BackoffOptions
|
||||
|
||||
/**
|
||||
* @see [[BackoffOnStopOptions.withFinalStopMessage()]]
|
||||
*/
|
||||
def withFinalStopMessage(isFinalStopMessage: Any ⇒ Boolean): BackoffOptions
|
||||
|
||||
/**
|
||||
* Returns the props to create the back-off supervisor.
|
||||
*/
|
||||
private[akka] def props: Props
|
||||
}
|
||||
|
||||
private final case class BackoffOptionsImpl(
|
||||
backoffType: BackoffType = RestartImpliesFailure,
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double,
|
||||
reset: Option[BackoffReset] = None,
|
||||
supervisorStrategy: OneForOneStrategy = OneForOneStrategy()(SupervisorStrategy.defaultStrategy.decider),
|
||||
replyWhileStopped: Option[Any] = None,
|
||||
finalStopMessage: Option[Any ⇒ Boolean] = None
|
||||
) extends akka.pattern.BackoffOptions {
|
||||
|
||||
val backoffReset = reset.getOrElse(AutoReset(minBackoff))
|
||||
|
||||
def withAutoReset(resetBackoff: FiniteDuration) = copy(reset = Some(AutoReset(resetBackoff)))
|
||||
def withManualReset = copy(reset = Some(ManualReset))
|
||||
def withSupervisorStrategy(supervisorStrategy: OneForOneStrategy) = copy(supervisorStrategy = supervisorStrategy)
|
||||
def withDefaultStoppingStrategy = copy(supervisorStrategy = OneForOneStrategy(supervisorStrategy.maxNrOfRetries)(SupervisorStrategy.stoppingStrategy.decider))
|
||||
def withReplyWhileStopped(replyWhileStopped: Any) = copy(replyWhileStopped = Some(replyWhileStopped))
|
||||
def withMaxNrOfRetries(maxNrOfRetries: Int) = copy(supervisorStrategy = supervisorStrategy.withMaxNrOfRetries(maxNrOfRetries))
|
||||
def withFinalStopMessage(action: Any ⇒ Boolean) = copy(finalStopMessage = Some(action))
|
||||
|
||||
def 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")
|
||||
backoffReset match {
|
||||
case AutoReset(resetBackoff) ⇒
|
||||
require(minBackoff <= resetBackoff && resetBackoff <= maxBackoff)
|
||||
case _ ⇒ // ignore
|
||||
}
|
||||
|
||||
backoffType match {
|
||||
//onFailure method in companion object
|
||||
case RestartImpliesFailure ⇒
|
||||
Props(new BackoffOnRestartSupervisor(childProps, childName, minBackoff, maxBackoff, backoffReset, randomFactor, supervisorStrategy, replyWhileStopped))
|
||||
//onStop method in companion object
|
||||
case StopImpliesFailure ⇒
|
||||
Props(new BackoffOnStopSupervisor(childProps, childName, minBackoff, maxBackoff, backoffReset, randomFactor, supervisorStrategy, replyWhileStopped, finalStopMessage))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed trait BackoffType
|
||||
private final case object StopImpliesFailure extends BackoffType
|
||||
private final case object RestartImpliesFailure extends BackoffType
|
||||
|
|
@ -4,29 +4,17 @@
|
|||
|
||||
package akka.pattern
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
import akka.util.JavaDurationConverters._
|
||||
import akka.actor.{ OneForOneStrategy, Props, SupervisorStrategy }
|
||||
import akka.annotation.DoNotInherit
|
||||
import akka.pattern.internal.{ BackoffOnRestartSupervisor, BackoffOnStopSupervisor }
|
||||
import akka.util.JavaDurationConverters._
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
|
||||
/**
|
||||
* Builds back-off options for creating a back-off supervisor.
|
||||
* You can pass `BackoffOptions` to `akka.pattern.BackoffSupervisor.props`.
|
||||
* An example of creating back-off options:
|
||||
* {{{
|
||||
* Backoff.onFailure(childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
* .withManualReset
|
||||
* .withSupervisorStrategy(
|
||||
* OneforOneStrategy(){
|
||||
* case e: GivingUpException => Stop
|
||||
* case e: RetryableException => Restart
|
||||
* }
|
||||
* )
|
||||
* .withReplyWhileStopped(TheSystemIsDown)
|
||||
*
|
||||
* }}}
|
||||
* Backoff options allow to specify a number of properties for backoff supervisors.
|
||||
*/
|
||||
object Backoff {
|
||||
object BackoffOpts {
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
*
|
||||
|
|
@ -61,84 +49,25 @@ object Backoff {
|
|||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOnFailureOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*
|
||||
*/
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
BackoffOptionsImpl(RestartImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor).withMaxNrOfRetries(maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
*
|
||||
* This explicit supervisor behaves similarly to the normal implicit supervision where
|
||||
* if an actor throws an exception, the decider on the supervisor will decide when to
|
||||
* `Stop`, `Restart`, `Escalate`, `Resume` the child actor.
|
||||
*
|
||||
* When the `Restart` directive is specified, the supervisor will delay the restart
|
||||
* using an exponential back off strategy (bounded by minBackoff and maxBackoff).
|
||||
*
|
||||
* This supervisor is intended to be transparent to both the child actor and external actors.
|
||||
* Where external actors can send messages to the supervisor as if it was the child and the
|
||||
* messages will be forwarded. And when the child is `Terminated`, the supervisor is also
|
||||
* `Terminated`.
|
||||
* Transparent to the child means that the child does not have to be aware that it is being
|
||||
* supervised specifically by this actor. Just like it does
|
||||
* not need to know when it is being supervised by the usual implicit supervisors.
|
||||
* The only caveat is that the `ActorRef` of the child is not stable, so any user storing the
|
||||
* `sender()` `ActorRef` from the child response may eventually not be able to communicate with
|
||||
* the stored `ActorRef`. In general all messages to the child should be directed through this actor.
|
||||
*
|
||||
* An example of where this supervisor might be used is when you may have an actor that is
|
||||
* responsible for continuously polling on a server for some resource that sometimes may be down.
|
||||
* Instead of hammering the server continuously when the resource is unavailable, the actor will
|
||||
* be restarted with an exponentially increasing back off until the resource is available again.
|
||||
*
|
||||
* '''***
|
||||
* This supervisor should not be used with `Akka Persistence` child actors.
|
||||
* `Akka Persistence` actors shutdown unconditionally on `persistFailure()`s rather
|
||||
* than throw an exception on a failure like normal actors.
|
||||
* [[#onStop]] should be used instead for cases where the child actor
|
||||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
BackoffOptionsImpl(RestartImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
randomFactor: Double): BackoffOnFailureOptions =
|
||||
BackoffOnFailureOptionsImpl(childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
|
|
@ -174,84 +103,25 @@ object Backoff {
|
|||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOnFailureOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
onFailure(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to restart on failure.
|
||||
*
|
||||
* This explicit supervisor behaves similarly to the normal implicit supervision where
|
||||
* if an actor throws an exception, the decider on the supervisor will decide when to
|
||||
* `Stop`, `Restart`, `Escalate`, `Resume` the child actor.
|
||||
*
|
||||
* When the `Restart` directive is specified, the supervisor will delay the restart
|
||||
* using an exponential back off strategy (bounded by minBackoff and maxBackoff).
|
||||
*
|
||||
* This supervisor is intended to be transparent to both the child actor and external actors.
|
||||
* Where external actors can send messages to the supervisor as if it was the child and the
|
||||
* messages will be forwarded. And when the child is `Terminated`, the supervisor is also
|
||||
* `Terminated`.
|
||||
* Transparent to the child means that the child does not have to be aware that it is being
|
||||
* supervised specifically by this actor. Just like it does
|
||||
* not need to know when it is being supervised by the usual implicit supervisors.
|
||||
* The only caveat is that the `ActorRef` of the child is not stable, so any user storing the
|
||||
* `sender()` `ActorRef` from the child response may eventually not be able to communicate with
|
||||
* the stored `ActorRef`. In general all messages to the child should be directed through this actor.
|
||||
*
|
||||
* An example of where this supervisor might be used is when you may have an actor that is
|
||||
* responsible for continuously polling on a server for some resource that sometimes may be down.
|
||||
* Instead of hammering the server continuously when the resource is unavailable, the actor will
|
||||
* be restarted with an exponentially increasing back off until the resource is available again.
|
||||
*
|
||||
* '''***
|
||||
* This supervisor should not be used with `Akka Persistence` child actors.
|
||||
* `Akka Persistence` actors shutdown unconditionally on `persistFailure()`s rather
|
||||
* than throw an exception on a failure like normal actors.
|
||||
* [[#onStop]] should be used instead for cases where the child actor
|
||||
* terminates itself as a failure signal instead of the normal behavior of throwing an exception.
|
||||
* ***'''
|
||||
* You can define another
|
||||
* supervision strategy by using `akka.pattern.BackoffOptions.withSupervisorStrategy` on [[akka.pattern.BackoffOptions]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@Deprecated
|
||||
def onFailure(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
onFailure(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, -1)
|
||||
randomFactor: Double): BackoffOnFailureOptions =
|
||||
onFailure(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor)
|
||||
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
|
|
@ -292,92 +162,27 @@ object Backoff {
|
|||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* [[BackoffOnStopOptions#withSupervisorStrategy]] or [[BackoffOnStopOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*/
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
BackoffOptionsImpl(StopImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor).withMaxNrOfRetries(maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
*
|
||||
* This actor can be used to supervise a child actor and start it again
|
||||
* after a back-off duration if the child actor is stopped.
|
||||
*
|
||||
* This is useful in situations where the re-start of the child actor should be
|
||||
* delayed e.g. in order to give an external resource time to recover before the
|
||||
* child actor tries contacting it again (after being restarted).
|
||||
*
|
||||
* Specifically this pattern is useful for persistent actors,
|
||||
* which are stopped in case of persistence failures.
|
||||
* Just restarting them immediately would probably fail again (since the data
|
||||
* store is probably unavailable). It is better to try again after a delay.
|
||||
*
|
||||
* It supports exponential back-off between the given `minBackoff` and
|
||||
* `maxBackoff` durations. For example, if `minBackoff` is 3 seconds and
|
||||
* `maxBackoff` 30 seconds the start attempts will be delayed with
|
||||
* 3, 6, 12, 24, 30, 30 seconds. The exponential back-off counter is reset
|
||||
* if the actor is not terminated within the `minBackoff` duration.
|
||||
*
|
||||
* In addition to the calculated exponential back-off an additional
|
||||
* random delay based the given `randomFactor` is added, e.g. 0.2 adds up to 20%
|
||||
* delay. The reason for adding a random delay is to avoid that all failing
|
||||
* actors hit the backend resource at the same time.
|
||||
*
|
||||
* You can retrieve the current child `ActorRef` by sending `BackoffSupervisor.GetCurrentChild`
|
||||
* message to this actor and it will reply with [[akka.pattern.BackoffSupervisor.CurrentChild]]
|
||||
* containing the `ActorRef` of the current child, if any.
|
||||
*
|
||||
* The `BackoffSupervisor`delegates all messages from the child to the parent of the
|
||||
* `BackoffSupervisor`, with the supervisor as sender.
|
||||
*
|
||||
* The `BackoffSupervisor` forwards all other messages to the child, if it is currently running.
|
||||
*
|
||||
* The child can stop itself and send a [[akka.actor.PoisonPill]] to the parent supervisor
|
||||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
BackoffOptionsImpl(StopImpliesFailure, childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
randomFactor: Double): BackoffOnStopOptions =
|
||||
BackoffOnStopOptionsImpl(childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
|
|
@ -418,161 +223,80 @@ object Backoff {
|
|||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* [[BackoffOnStopOptions#withSupervisorStrategy]] or [[BackoffOnStopOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double,
|
||||
maxNrOfRetries: Int): BackoffOptions =
|
||||
onStop(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, maxNrOfRetries)
|
||||
|
||||
/**
|
||||
* Java API: Back-off options for creating a back-off supervisor actor that expects a child actor to stop on failure.
|
||||
*
|
||||
* This actor can be used to supervise a child actor and start it again
|
||||
* after a back-off duration if the child actor is stopped.
|
||||
*
|
||||
* This is useful in situations where the re-start of the child actor should be
|
||||
* delayed e.g. in order to give an external resource time to recover before the
|
||||
* child actor tries contacting it again (after being restarted).
|
||||
*
|
||||
* Specifically this pattern is useful for persistent actors,
|
||||
* which are stopped in case of persistence failures.
|
||||
* Just restarting them immediately would probably fail again (since the data
|
||||
* store is probably unavailable). It is better to try again after a delay.
|
||||
*
|
||||
* It supports exponential back-off between the given `minBackoff` and
|
||||
* `maxBackoff` durations. For example, if `minBackoff` is 3 seconds and
|
||||
* `maxBackoff` 30 seconds the start attempts will be delayed with
|
||||
* 3, 6, 12, 24, 30, 30 seconds. The exponential back-off counter is reset
|
||||
* if the actor is not terminated within the `minBackoff` duration.
|
||||
*
|
||||
* In addition to the calculated exponential back-off an additional
|
||||
* random delay based the given `randomFactor` is added, e.g. 0.2 adds up to 20%
|
||||
* delay. The reason for adding a random delay is to avoid that all failing
|
||||
* actors hit the backend resource at the same time.
|
||||
*
|
||||
* You can retrieve the current child `ActorRef` by sending `BackoffSupervisor.GetCurrentChild`
|
||||
* message to this actor and it will reply with [[akka.pattern.BackoffSupervisor.CurrentChild]]
|
||||
* containing the `ActorRef` of the current child, if any.
|
||||
*
|
||||
* The `BackoffSupervisor`delegates all messages from the child to the parent of the
|
||||
* `BackoffSupervisor`, with the supervisor as sender.
|
||||
*
|
||||
* The `BackoffSupervisor` forwards all other messages to the child, if it is currently running.
|
||||
*
|
||||
* The child can stop itself and send a [[akka.actor.PoisonPill]] to the parent supervisor
|
||||
* if it wants to do an intentional stop.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervisionStrategy, which can be changed by using
|
||||
* [[BackoffOptions#withSupervisorStrategy]] or [[BackoffOptions#withDefaultStoppingStrategy]]. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@Deprecated
|
||||
def onStop(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: java.time.Duration,
|
||||
maxBackoff: java.time.Duration,
|
||||
randomFactor: Double): BackoffOptions =
|
||||
onStop(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor, -1)
|
||||
|
||||
randomFactor: Double): BackoffOnStopOptions =
|
||||
onStop(childProps, childName, minBackoff.asScala, maxBackoff.asScala, randomFactor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a back-off supervisor actor. Start with `Backoff.onStop` or `Backoff.onFailure`.
|
||||
* BackoffOptions is immutable, so be sure to chain methods like:
|
||||
* {{{
|
||||
* val options = Backoff.onFailure(childProps, childName, minBackoff, maxBackoff, randomFactor)
|
||||
* .withManualReset
|
||||
* context.actorOf(BackoffSupervisor.props(options), name)
|
||||
* }}}
|
||||
* Not for user extension
|
||||
*/
|
||||
@DoNotInherit
|
||||
trait BackoffOptions {
|
||||
private[akka] sealed trait ExtendedBackoffOptions[T <: ExtendedBackoffOptions[T]] {
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with automatic back-off reset.
|
||||
* The back-off algorithm is reset if the child does not crash within the specified `resetBackoff`.
|
||||
*
|
||||
* @param resetBackoff The back-off is reset if the child does not crash within this duration.
|
||||
*/
|
||||
def withAutoReset(resetBackoff: FiniteDuration): BackoffOptions
|
||||
def withAutoReset(resetBackoff: FiniteDuration): T
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with manual back-off reset. The back-off is only reset
|
||||
* if the child sends a `BackoffSupervisor.Reset` to its parent (the backoff-supervisor actor).
|
||||
*/
|
||||
def withManualReset: BackoffOptions
|
||||
def withManualReset: T
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with the supervisorStrategy.
|
||||
*
|
||||
* @param supervisorStrategy the supervisorStrategy that the back-off supervisor will use.
|
||||
* The default supervisor strategy is used as fallback if the specified supervisorStrategy (its decider)
|
||||
* does not explicitly handle an exception. As the BackoffSupervisor creates a separate actor to handle the
|
||||
* backoff process, only a [[OneForOneStrategy]] makes sense here.
|
||||
* Note that changing the strategy will replace the previously defined maxNrOfRetries.
|
||||
* The default supervisor strategy is used as fallback if the specified supervisorStrategy (its decider)
|
||||
* does not explicitly handle an exception. As the BackoffSupervisor creates a separate actor to handle the
|
||||
* backoff process, only a [[OneForOneStrategy]] makes sense here.
|
||||
* Note that changing the strategy will replace the previously defined maxNrOfRetries.
|
||||
*/
|
||||
def withSupervisorStrategy(supervisorStrategy: OneForOneStrategy): BackoffOptions
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with a default `SupervisorStrategy.stoppingStrategy`.
|
||||
* The default supervisor strategy is used as fallback for throwables not handled by `SupervisorStrategy.stoppingStrategy`.
|
||||
*/
|
||||
def withDefaultStoppingStrategy: BackoffOptions
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with a constant reply to messages that the supervisor receives while its
|
||||
* child is stopped. By default, a message received while the child is stopped is forwarded to `deadLetters`.
|
||||
* With this option, the supervisor will reply to the sender instead.
|
||||
* @param replyWhileStopped The message that the supervisor will send in response to all messages while
|
||||
* its child is stopped.
|
||||
*/
|
||||
def withReplyWhileStopped(replyWhileStopped: Any): BackoffOptions
|
||||
|
||||
/**
|
||||
* Predicate evaluated for each message, if it returns true and the supervised actor is
|
||||
* stopped then the supervisor will stop its self. If it returns true while
|
||||
* the supervised actor is running then it will be forwarded to the supervised actor and
|
||||
* when the supervised actor stops its self the supervisor will stop its self.
|
||||
*/
|
||||
def withFinalStopMessage(isFinalStopMessage: Any ⇒ Boolean): BackoffOptions
|
||||
def withSupervisorStrategy(supervisorStrategy: OneForOneStrategy): T
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with a maximum number of retries to restart the child actor.
|
||||
* By default, the supervisor will retry infinitely.
|
||||
* With this option, the supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* @param maxNrOfRetries the number of times a child actor is allowed to be restarted, negative value means no limit,
|
||||
* if the limit is exceeded the child actor is stopped
|
||||
*
|
||||
* @param maxNrOfRetries the number of times a child actor is allowed to be restarted.
|
||||
* If negative, the value is unbounded, otherwise the provided
|
||||
* limit is used. If the limit is exceeded the child actor will be stopped.
|
||||
*/
|
||||
def withMaxNrOfRetries(maxNrOfRetries: Int): BackoffOptions
|
||||
def withMaxNrOfRetries(maxNrOfRetries: Int): T
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with a constant reply to messages that the supervisor receives while its
|
||||
* child is stopped. By default, a message received while the child is stopped is forwarded to `deadLetters`.
|
||||
* With this option, the supervisor will reply to the sender instead.
|
||||
*
|
||||
* @param replyWhileStopped The message that the supervisor will send in response to all messages while
|
||||
* its child is stopped.
|
||||
*/
|
||||
def withReplyWhileStopped(replyWhileStopped: Any): T
|
||||
|
||||
/**
|
||||
* Returns the props to create the back-off supervisor.
|
||||
|
|
@ -580,8 +304,28 @@ trait BackoffOptions {
|
|||
private[akka] def props: Props
|
||||
}
|
||||
|
||||
private final case class BackoffOptionsImpl(
|
||||
backoffType: BackoffType = RestartImpliesFailure,
|
||||
@DoNotInherit
|
||||
sealed trait BackoffOnStopOptions extends ExtendedBackoffOptions[BackoffOnStopOptions] {
|
||||
|
||||
/**
|
||||
* Returns a new BackoffOptions with a default `SupervisorStrategy.stoppingStrategy`.
|
||||
* The default supervisor strategy is used as fallback for throwables not handled by `SupervisorStrategy.stoppingStrategy`.
|
||||
*/
|
||||
def withDefaultStoppingStrategy: BackoffOnStopOptions
|
||||
|
||||
/**
|
||||
* Predicate evaluated for each message, if it returns true and the supervised actor is
|
||||
* stopped then the supervisor will stop its self. If it returns true while
|
||||
* the supervised actor is running then it will be forwarded to the supervised actor and
|
||||
* when the supervised actor stops its self the supervisor will stop its self.
|
||||
*/
|
||||
def withFinalStopMessage(isFinalStopMessage: Any ⇒ Boolean): BackoffOnStopOptions
|
||||
}
|
||||
|
||||
@DoNotInherit
|
||||
sealed trait BackoffOnFailureOptions extends ExtendedBackoffOptions[BackoffOnFailureOptions]
|
||||
|
||||
private final case class BackoffOnStopOptionsImpl[T](
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
|
|
@ -591,19 +335,22 @@ private final case class BackoffOptionsImpl(
|
|||
supervisorStrategy: OneForOneStrategy = OneForOneStrategy()(SupervisorStrategy.defaultStrategy.decider),
|
||||
replyWhileStopped: Option[Any] = None,
|
||||
finalStopMessage: Option[Any ⇒ Boolean] = None
|
||||
) extends BackoffOptions {
|
||||
) extends BackoffOnStopOptions {
|
||||
|
||||
val backoffReset = reset.getOrElse(AutoReset(minBackoff))
|
||||
private val backoffReset = reset.getOrElse(AutoReset(minBackoff))
|
||||
|
||||
// default
|
||||
def withAutoReset(resetBackoff: FiniteDuration) = copy(reset = Some(AutoReset(resetBackoff)))
|
||||
def withManualReset = copy(reset = Some(ManualReset))
|
||||
def withSupervisorStrategy(supervisorStrategy: OneForOneStrategy) = copy(supervisorStrategy = supervisorStrategy)
|
||||
def withDefaultStoppingStrategy = copy(supervisorStrategy = OneForOneStrategy(supervisorStrategy.maxNrOfRetries)(SupervisorStrategy.stoppingStrategy.decider))
|
||||
def withReplyWhileStopped(replyWhileStopped: Any) = copy(replyWhileStopped = Some(replyWhileStopped))
|
||||
def withMaxNrOfRetries(maxNrOfRetries: Int) = copy(supervisorStrategy = supervisorStrategy.withMaxNrOfRetries(maxNrOfRetries))
|
||||
|
||||
// additional
|
||||
def withDefaultStoppingStrategy = copy(supervisorStrategy = OneForOneStrategy(supervisorStrategy.maxNrOfRetries)(SupervisorStrategy.stoppingStrategy.decider))
|
||||
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")
|
||||
|
|
@ -613,20 +360,43 @@ private final case class BackoffOptionsImpl(
|
|||
case _ ⇒ // ignore
|
||||
}
|
||||
|
||||
backoffType match {
|
||||
//onFailure method in companion object
|
||||
case RestartImpliesFailure ⇒
|
||||
Props(new BackoffOnRestartSupervisor(childProps, childName, minBackoff, maxBackoff, backoffReset, randomFactor, supervisorStrategy, replyWhileStopped, finalStopMessage))
|
||||
//onStop method in companion object
|
||||
case StopImpliesFailure ⇒
|
||||
Props(new BackoffSupervisor(childProps, childName, minBackoff, maxBackoff, backoffReset, randomFactor, supervisorStrategy, replyWhileStopped, finalStopMessage))
|
||||
}
|
||||
Props(new BackoffOnStopSupervisor(childProps, childName, minBackoff, maxBackoff, backoffReset, randomFactor, supervisorStrategy, replyWhileStopped, finalStopMessage))
|
||||
}
|
||||
}
|
||||
|
||||
private sealed trait BackoffType
|
||||
private final case object StopImpliesFailure extends BackoffType
|
||||
private final case object RestartImpliesFailure extends BackoffType
|
||||
private final case class BackoffOnFailureOptionsImpl[T](
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double,
|
||||
reset: Option[BackoffReset] = None,
|
||||
supervisorStrategy: OneForOneStrategy = OneForOneStrategy()(SupervisorStrategy.defaultStrategy.decider),
|
||||
replyWhileStopped: Option[Any] = None
|
||||
) extends BackoffOnFailureOptions {
|
||||
|
||||
private val backoffReset = reset.getOrElse(AutoReset(minBackoff))
|
||||
|
||||
// default
|
||||
def withAutoReset(resetBackoff: FiniteDuration) = copy(reset = Some(AutoReset(resetBackoff)))
|
||||
def withManualReset = copy(reset = Some(ManualReset))
|
||||
def withSupervisorStrategy(supervisorStrategy: OneForOneStrategy) = copy(supervisorStrategy = supervisorStrategy)
|
||||
def withReplyWhileStopped(replyWhileStopped: Any) = copy(replyWhileStopped = Some(replyWhileStopped))
|
||||
def withMaxNrOfRetries(maxNrOfRetries: Int) = copy(supervisorStrategy = supervisorStrategy.withMaxNrOfRetries(maxNrOfRetries))
|
||||
|
||||
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")
|
||||
backoffReset match {
|
||||
case AutoReset(resetBackoff) ⇒
|
||||
require(minBackoff <= resetBackoff && resetBackoff <= maxBackoff)
|
||||
case _ ⇒ // ignore
|
||||
}
|
||||
|
||||
Props(new BackoffOnRestartSupervisor(childProps, childName, minBackoff, maxBackoff, backoffReset, randomFactor, supervisorStrategy, replyWhileStopped))
|
||||
}
|
||||
}
|
||||
|
||||
private[akka] sealed trait BackoffReset
|
||||
private[akka] final case object ManualReset extends BackoffReset
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
package akka.pattern
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
|
||||
import akka.actor.{ Actor, ActorLogging, ActorRef, DeadLetterSuppression, OneForOneStrategy, Props, SupervisorStrategy, Terminated }
|
||||
import akka.actor.SupervisorStrategy.{ Directive, Escalate }
|
||||
import akka.actor.{ ActorRef, DeadLetterSuppression, OneForOneStrategy, Props, SupervisorStrategy }
|
||||
import akka.pattern.internal.BackoffOnStopSupervisor
|
||||
import akka.util.JavaDurationConverters._
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
|
|
@ -17,22 +17,23 @@ import scala.util.Try
|
|||
object BackoffSupervisor {
|
||||
|
||||
/**
|
||||
* Props for creating a [[BackoffSupervisor]] actor.
|
||||
* Props for creating a `BackoffSupervisor` actor.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervision strategy, i.e.
|
||||
* most exceptions will immediately restart the child. You can define another
|
||||
* supervision strategy by using [[#propsWithSupervisorStrategy]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@deprecated("Use props with BackoffOpts instead", since = "2.5.22")
|
||||
def props(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
|
|
@ -43,25 +44,26 @@ object BackoffSupervisor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Props for creating a [[BackoffSupervisor]] actor.
|
||||
* Props for creating a `BackoffSupervisor` actor.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervision strategy, i.e.
|
||||
* most exceptions will immediately restart the child. You can define another
|
||||
* supervision strategy by using [[#propsWithSupervisorStrategy]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*/
|
||||
@deprecated("Use props with BackoffOpts instead", since = "2.5.22")
|
||||
def props(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
|
|
@ -77,22 +79,23 @@ object BackoffSupervisor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Props for creating a [[BackoffSupervisor]] actor.
|
||||
* Props for creating a `BackoffSupervisor` actor.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervision strategy, i.e.
|
||||
* most exceptions will immediately restart the child. You can define another
|
||||
* supervision strategy by using [[#propsWithSupervisorStrategy]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
*/
|
||||
@deprecated("Use props with BackoffOpts instead", since = "2.5.22")
|
||||
def props(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
|
|
@ -103,25 +106,26 @@ object BackoffSupervisor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Props for creating a [[BackoffSupervisor]] actor.
|
||||
* Props for creating a `BackoffSupervisor` actor.
|
||||
*
|
||||
* Exceptions in the child are handled with the default supervision strategy, i.e.
|
||||
* most exceptions will immediately restart the child. You can define another
|
||||
* supervision strategy by using [[#propsWithSupervisorStrategy]].
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param maxNrOfRetries maximum number of attempts to restart the child actor.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
* The supervisor will terminate itself after the maxNoOfRetries is reached.
|
||||
* In order to restart infinitely pass in `-1`.
|
||||
*/
|
||||
@deprecated("Use props with BackoffOpts instead", since = "2.5.22")
|
||||
def props(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
|
|
@ -133,26 +137,27 @@ object BackoffSupervisor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Props for creating a [[BackoffSupervisor]] actor with a custom
|
||||
* Props for creating a `BackoffSupervisor` actor with a custom
|
||||
* supervision strategy.
|
||||
*
|
||||
* Exceptions in the child are handled with the given `supervisionStrategy`. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param strategy the supervision strategy to use for handling exceptions
|
||||
* in the child. As the BackoffSupervisor creates a separate actor to handle the
|
||||
* backoff process, only a [[OneForOneStrategy]] makes sense here.
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param strategy the supervision strategy to use for handling exceptions
|
||||
* in the child. As the BackoffSupervisor creates a separate actor to handle the
|
||||
* backoff process, only a [[OneForOneStrategy]] makes sense here.
|
||||
*/
|
||||
@deprecated("Use props with BackoffOpts instead", since = "2.5.22")
|
||||
def propsWithSupervisorStrategy(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
|
|
@ -163,30 +168,31 @@ object BackoffSupervisor {
|
|||
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")
|
||||
Props(new BackoffSupervisor(childProps, childName, minBackoff, maxBackoff, randomFactor, strategy))
|
||||
Props(new BackoffOnStopSupervisor(childProps, childName, minBackoff, maxBackoff, AutoReset(minBackoff), randomFactor, strategy, None, None))
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for creating a [[BackoffSupervisor]] actor with a custom
|
||||
* Props for creating a `BackoffSupervisor` actor with a custom
|
||||
* supervision strategy.
|
||||
*
|
||||
* Exceptions in the child are handled with the given `supervisionStrategy`. A
|
||||
* `Restart` will perform a normal immediate restart of the child. A `Stop` will
|
||||
* stop the child, but it will be started again after the back-off duration.
|
||||
*
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param childProps the [[akka.actor.Props]] of the child actor that
|
||||
* will be started and supervised
|
||||
* @param childName name of the child actor
|
||||
* @param minBackoff minimum (initial) duration until the child actor will
|
||||
* started again, if it is terminated
|
||||
* @param maxBackoff the exponential back-off is capped to this duration
|
||||
* @param randomFactor after calculation of the exponential back-off an additional
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param strategy the supervision strategy to use for handling exceptions
|
||||
* in the child. As the BackoffSupervisor creates a separate actor to handle the
|
||||
* backoff process, only a [[OneForOneStrategy]] makes sense here.
|
||||
* random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay.
|
||||
* In order to skip this additional delay pass in `0`.
|
||||
* @param strategy the supervision strategy to use for handling exceptions
|
||||
* in the child. As the BackoffSupervisor creates a separate actor to handle the
|
||||
* backoff process, only a [[OneForOneStrategy]] makes sense here.
|
||||
*/
|
||||
@deprecated("Use props with BackoffOpts instead", since = "2.5.22")
|
||||
def propsWithSupervisorStrategy(
|
||||
childProps: Props,
|
||||
childName: String,
|
||||
|
|
@ -198,26 +204,41 @@ object BackoffSupervisor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Props for creating a [[BackoffSupervisor]] actor from [[BackoffOptions]].
|
||||
* Props for creating a `BackoffSupervisor` actor from [[BackoffOptions]].
|
||||
*
|
||||
* @param options the [[BackoffOptions]] that specify how to construct a backoff-supervisor.
|
||||
*/
|
||||
@deprecated("Use new API from BackoffOpts object instead", since = "2.5.22")
|
||||
def props(options: BackoffOptions): Props = options.props
|
||||
|
||||
/**
|
||||
* Send this message to the [[BackoffSupervisor]] and it will reply with
|
||||
* Props for creating a `BackoffSupervisor` actor from [[BackoffOnStopOptions]].
|
||||
*
|
||||
* @param options the [[BackoffOnStopOptions]] that specify how to construct a backoff-supervisor.
|
||||
*/
|
||||
def props(options: BackoffOnStopOptions): Props = options.props
|
||||
|
||||
/**
|
||||
* Props for creating a `BackoffSupervisor` actor from [[BackoffOnFailureOptions]].
|
||||
*
|
||||
* @param options the [[BackoffOnFailureOptions]] that specify how to construct a backoff-supervisor.
|
||||
*/
|
||||
def props(options: BackoffOnFailureOptions): Props = options.props
|
||||
|
||||
/**
|
||||
* Send this message to the `BackoffSupervisor` and it will reply with
|
||||
* [[BackoffSupervisor.CurrentChild]] containing the `ActorRef` of the current child, if any.
|
||||
*/
|
||||
final case object GetCurrentChild
|
||||
|
||||
/**
|
||||
* Java API: Send this message to the [[BackoffSupervisor]] and it will reply with
|
||||
* Java API: Send this message to the `BackoffSupervisor` and it will reply with
|
||||
* [[BackoffSupervisor.CurrentChild]] containing the `ActorRef` of the current child, if any.
|
||||
*/
|
||||
def getCurrentChild = GetCurrentChild
|
||||
|
||||
/**
|
||||
* Send this message to the [[BackoffSupervisor]] and it will reply with
|
||||
* Send this message to the `BackoffSupervisor` and it will reply with
|
||||
* [[BackoffSupervisor.CurrentChild]] containing the `ActorRef` of the current child, if any.
|
||||
*/
|
||||
final case class CurrentChild(ref: Option[ActorRef]) {
|
||||
|
|
@ -228,25 +249,25 @@ object BackoffSupervisor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Send this message to the [[BackoffSupervisor]] and it will reset the back-off.
|
||||
* Send this message to the `BackoffSupervisor` and it will reset the back-off.
|
||||
* This should be used in conjunction with `withManualReset` in [[BackoffOptions]].
|
||||
*/
|
||||
final case object Reset
|
||||
|
||||
/**
|
||||
* Java API: Send this message to the [[BackoffSupervisor]] and it will reset the back-off.
|
||||
* Java API: Send this message to the `BackoffSupervisor` and it will reset the back-off.
|
||||
* This should be used in conjunction with `withManualReset` in [[BackoffOptions]].
|
||||
*/
|
||||
def reset = Reset
|
||||
|
||||
/**
|
||||
* Send this message to the [[BackoffSupervisor]] and it will reply with
|
||||
* Send this message to the `BackoffSupervisor` and it will reply with
|
||||
* [[BackoffSupervisor.RestartCount]] containing the current restart count.
|
||||
*/
|
||||
final case object GetRestartCount
|
||||
|
||||
/**
|
||||
* Java API: Send this message to the [[BackoffSupervisor]] and it will reply with
|
||||
* Java API: Send this message to the `BackoffSupervisor` and it will reply with
|
||||
* [[BackoffSupervisor.RestartCount]] containing the current restart count.
|
||||
*/
|
||||
def getRestartCount = GetRestartCount
|
||||
|
|
@ -278,39 +299,19 @@ object BackoffSupervisor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
// for backwards compability
|
||||
@deprecated("Use `BackoffSupervisor.props` method instead", since = "2.5.22")
|
||||
final class BackoffSupervisor(
|
||||
val childProps: Props,
|
||||
val childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
val reset: BackoffReset,
|
||||
randomFactor: Double,
|
||||
strategy: SupervisorStrategy,
|
||||
val replyWhileStopped: Option[Any],
|
||||
val finalStopMessage: Option[Any ⇒ Boolean])
|
||||
extends Actor with HandleBackoff
|
||||
with ActorLogging {
|
||||
|
||||
import BackoffSupervisor._
|
||||
import context.dispatcher
|
||||
|
||||
// to keep binary compatibility with 2.4.1
|
||||
override val supervisorStrategy = strategy match {
|
||||
case oneForOne: OneForOneStrategy ⇒
|
||||
OneForOneStrategy(oneForOne.maxNrOfRetries, oneForOne.withinTimeRange, oneForOne.loggingEnabled) {
|
||||
case ex ⇒
|
||||
val defaultDirective: Directive =
|
||||
super.supervisorStrategy.decider.applyOrElse(ex, (_: Any) ⇒ Escalate)
|
||||
|
||||
strategy.decider.applyOrElse(ex, (_: Any) ⇒ defaultDirective)
|
||||
}
|
||||
case s ⇒ s
|
||||
}
|
||||
override val childProps: Props,
|
||||
override val childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
override val reset: BackoffReset,
|
||||
randomFactor: Double,
|
||||
strategy: SupervisorStrategy,
|
||||
val replyWhileStopped: Option[Any],
|
||||
val finalStopMessage: Option[Any ⇒ Boolean])
|
||||
extends BackoffOnStopSupervisor(childProps, childName, minBackoff, maxBackoff, reset, randomFactor, strategy, replyWhileStopped, finalStopMessage) {
|
||||
|
||||
// for binary compatibility with 2.5.18
|
||||
def this(
|
||||
|
|
@ -341,105 +342,4 @@ final class BackoffSupervisor(
|
|||
maxBackoff: FiniteDuration,
|
||||
randomFactor: Double) =
|
||||
this(childProps, childName, minBackoff, maxBackoff, randomFactor, SupervisorStrategy.defaultStrategy)
|
||||
|
||||
def onTerminated: Receive = {
|
||||
case Terminated(ref) if child.contains(ref) ⇒
|
||||
child = None
|
||||
if (finalStopMessageReceived) {
|
||||
context.stop(self)
|
||||
} else {
|
||||
val maxNrOfRetries = strategy match {
|
||||
case oneForOne: OneForOneStrategy ⇒ oneForOne.maxNrOfRetries
|
||||
case _ ⇒ -1
|
||||
}
|
||||
|
||||
val nextRestartCount = restartCount + 1
|
||||
|
||||
if (maxNrOfRetries == -1 || nextRestartCount <= maxNrOfRetries) {
|
||||
val restartDelay = calculateDelay(restartCount, minBackoff, maxBackoff, randomFactor)
|
||||
context.system.scheduler.scheduleOnce(restartDelay, self, StartChild)
|
||||
restartCount = nextRestartCount
|
||||
} else {
|
||||
log.debug(s"Terminating on restart #{} which exceeds max allowed restarts ({})", nextRestartCount, maxNrOfRetries)
|
||||
context.stop(self)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def receive = onTerminated orElse handleBackoff
|
||||
}
|
||||
|
||||
private[akka] trait HandleBackoff { this: Actor ⇒
|
||||
def childProps: Props
|
||||
def childName: String
|
||||
def reset: BackoffReset
|
||||
def replyWhileStopped: Option[Any]
|
||||
def finalStopMessage: Option[Any ⇒ Boolean]
|
||||
|
||||
var child: Option[ActorRef] = None
|
||||
var restartCount = 0
|
||||
var finalStopMessageReceived = false
|
||||
|
||||
import BackoffSupervisor._
|
||||
import context.dispatcher
|
||||
|
||||
override def preStart(): Unit = startChild()
|
||||
|
||||
def startChild(): Unit = {
|
||||
if (child.isEmpty) {
|
||||
child = Some(context.watch(context.actorOf(childProps, childName)))
|
||||
}
|
||||
}
|
||||
|
||||
def handleBackoff: Receive = {
|
||||
case StartChild ⇒
|
||||
startChild()
|
||||
reset match {
|
||||
case AutoReset(resetBackoff) ⇒
|
||||
val _ = context.system.scheduler.scheduleOnce(resetBackoff, self, ResetRestartCount(restartCount))
|
||||
case _ ⇒ // ignore
|
||||
}
|
||||
|
||||
case Reset ⇒
|
||||
reset match {
|
||||
case ManualReset ⇒ restartCount = 0
|
||||
case msg ⇒ unhandled(msg)
|
||||
}
|
||||
|
||||
case ResetRestartCount(current) ⇒
|
||||
if (current == restartCount) {
|
||||
restartCount = 0
|
||||
}
|
||||
|
||||
case GetRestartCount ⇒
|
||||
sender() ! RestartCount(restartCount)
|
||||
|
||||
case GetCurrentChild ⇒
|
||||
sender() ! CurrentChild(child)
|
||||
|
||||
case msg if child.contains(sender()) ⇒
|
||||
// use the BackoffSupervisor as sender
|
||||
context.parent ! msg
|
||||
|
||||
case msg ⇒ child match {
|
||||
case Some(c) ⇒
|
||||
c.forward(msg)
|
||||
if (!finalStopMessageReceived && finalStopMessage.isDefined) {
|
||||
finalStopMessageReceived = finalStopMessage.get.apply(msg)
|
||||
}
|
||||
case None ⇒
|
||||
replyWhileStopped match {
|
||||
case None ⇒ context.system.deadLetters.forward(msg)
|
||||
case Some(r) ⇒ sender() ! r
|
||||
}
|
||||
finalStopMessage match {
|
||||
case None ⇒
|
||||
case Some(fsm) ⇒
|
||||
if (fsm(msg)) {
|
||||
context.stop(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
69
akka-actor/src/main/scala/akka/pattern/HandleBackoff.scala
Normal file
69
akka-actor/src/main/scala/akka/pattern/HandleBackoff.scala
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.pattern
|
||||
|
||||
import akka.actor.{ Actor, ActorRef, Props }
|
||||
import akka.annotation.InternalApi
|
||||
import akka.pattern.internal.{ BackoffOnRestartSupervisor, BackoffOnStopSupervisor }
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
* Implements basic backoff handling for [[BackoffOnRestartSupervisor]] and [[BackoffOnStopSupervisor]].
|
||||
*/
|
||||
@InternalApi private[akka] trait HandleBackoff {
|
||||
this: Actor ⇒
|
||||
def childProps: Props
|
||||
def childName: String
|
||||
def reset: BackoffReset
|
||||
protected def handleMessageToChild(m: Any): Unit
|
||||
|
||||
var child: Option[ActorRef] = None
|
||||
var restartCount = 0
|
||||
var finalStopMessageReceived = false
|
||||
|
||||
import BackoffSupervisor._
|
||||
import context.dispatcher
|
||||
|
||||
override def preStart(): Unit = startChild()
|
||||
|
||||
def startChild(): Unit = if (child.isEmpty) {
|
||||
child = Some(context.watch(context.actorOf(childProps, childName)))
|
||||
}
|
||||
|
||||
def handleBackoff: Actor.Receive = {
|
||||
case StartChild ⇒
|
||||
startChild()
|
||||
reset match {
|
||||
case AutoReset(resetBackoff) ⇒
|
||||
context.system.scheduler.scheduleOnce(resetBackoff, self, ResetRestartCount(restartCount))
|
||||
case _ ⇒ // ignore
|
||||
}
|
||||
|
||||
case Reset ⇒
|
||||
reset match {
|
||||
case ManualReset ⇒ restartCount = 0
|
||||
case msg ⇒ unhandled(msg)
|
||||
}
|
||||
|
||||
case ResetRestartCount(current) ⇒
|
||||
if (current == restartCount) {
|
||||
restartCount = 0
|
||||
}
|
||||
|
||||
case GetRestartCount ⇒
|
||||
sender() ! RestartCount(restartCount)
|
||||
|
||||
case GetCurrentChild ⇒
|
||||
sender() ! CurrentChild(child)
|
||||
|
||||
case msg if child.contains(sender()) ⇒
|
||||
// use the BackoffSupervisor as sender
|
||||
context.parent ! msg
|
||||
|
||||
case msg ⇒
|
||||
handleMessageToChild(msg)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,34 +2,36 @@
|
|||
* Copyright (C) 2015-2019 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.pattern
|
||||
package akka.pattern.internal
|
||||
|
||||
import akka.actor.SupervisorStrategy._
|
||||
import akka.actor.{ OneForOneStrategy, _ }
|
||||
import akka.annotation.InternalApi
|
||||
import akka.pattern.{ BackoffReset, BackoffSupervisor, HandleBackoff }
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import akka.actor._
|
||||
import akka.actor.OneForOneStrategy
|
||||
import akka.actor.SupervisorStrategy._
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
* 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``.
|
||||
*/
|
||||
private class BackoffOnRestartSupervisor(
|
||||
val childProps: Props,
|
||||
val childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
val reset: BackoffReset,
|
||||
randomFactor: Double,
|
||||
strategy: OneForOneStrategy,
|
||||
val replyWhileStopped: Option[Any],
|
||||
val finalStopMessage: Option[Any ⇒ Boolean])
|
||||
@InternalApi private[pattern] class BackoffOnRestartSupervisor(
|
||||
val childProps: Props,
|
||||
val childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
val reset: BackoffReset,
|
||||
randomFactor: Double,
|
||||
strategy: OneForOneStrategy,
|
||||
replyWhileStopped: Option[Any])
|
||||
extends Actor with HandleBackoff
|
||||
with ActorLogging {
|
||||
|
||||
import context._
|
||||
import BackoffSupervisor._
|
||||
import context._
|
||||
|
||||
override val supervisorStrategy = OneForOneStrategy(strategy.maxNrOfRetries, strategy.withinTimeRange, strategy.loggingEnabled) {
|
||||
case ex ⇒
|
||||
|
|
@ -81,6 +83,15 @@ private class BackoffOnRestartSupervisor(
|
|||
stop(self)
|
||||
}
|
||||
|
||||
def receive = onTerminated orElse handleBackoff
|
||||
def receive: Receive = onTerminated orElse handleBackoff
|
||||
|
||||
protected def handleMessageToChild(msg: Any): Unit = child match {
|
||||
case Some(c) ⇒
|
||||
c.forward(msg)
|
||||
case None ⇒
|
||||
replyWhileStopped match {
|
||||
case None ⇒ context.system.deadLetters.forward(msg)
|
||||
case Some(r) ⇒ sender() ! r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.pattern.internal
|
||||
|
||||
import akka.actor.SupervisorStrategy.{ Directive, Escalate }
|
||||
import akka.actor.{ Actor, ActorLogging, OneForOneStrategy, Props, SupervisorStrategy, Terminated }
|
||||
import akka.annotation.InternalApi
|
||||
import akka.pattern.{ BackoffReset, BackoffSupervisor, HandleBackoff }
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
* 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 `BackoffOpts.onStop`.
|
||||
*/
|
||||
@InternalApi private[pattern] class BackoffOnStopSupervisor(
|
||||
val childProps: Props,
|
||||
val childName: String,
|
||||
minBackoff: FiniteDuration,
|
||||
maxBackoff: FiniteDuration,
|
||||
val reset: BackoffReset,
|
||||
randomFactor: Double,
|
||||
strategy: SupervisorStrategy,
|
||||
replyWhileStopped: Option[Any],
|
||||
finalStopMessage: Option[Any ⇒ Boolean])
|
||||
extends Actor with HandleBackoff
|
||||
with ActorLogging {
|
||||
|
||||
import BackoffSupervisor._
|
||||
import context.dispatcher
|
||||
|
||||
override val supervisorStrategy = strategy match {
|
||||
case oneForOne: OneForOneStrategy ⇒
|
||||
OneForOneStrategy(oneForOne.maxNrOfRetries, oneForOne.withinTimeRange, oneForOne.loggingEnabled) {
|
||||
case ex ⇒
|
||||
val defaultDirective: Directive =
|
||||
super.supervisorStrategy.decider.applyOrElse(ex, (_: Any) ⇒ Escalate)
|
||||
|
||||
strategy.decider.applyOrElse(ex, (_: Any) ⇒ defaultDirective)
|
||||
}
|
||||
case s ⇒ s
|
||||
}
|
||||
|
||||
def onTerminated: Receive = {
|
||||
case Terminated(ref) if child.contains(ref) ⇒
|
||||
child = None
|
||||
if (finalStopMessageReceived) {
|
||||
context.stop(self)
|
||||
} else {
|
||||
val maxNrOfRetries = strategy match {
|
||||
case oneForOne: OneForOneStrategy ⇒ oneForOne.maxNrOfRetries
|
||||
case _ ⇒ -1
|
||||
}
|
||||
|
||||
val nextRestartCount = restartCount + 1
|
||||
|
||||
if (maxNrOfRetries == -1 || nextRestartCount <= maxNrOfRetries) {
|
||||
val restartDelay = calculateDelay(restartCount, minBackoff, maxBackoff, randomFactor)
|
||||
context.system.scheduler.scheduleOnce(restartDelay, self, StartChild)
|
||||
restartCount = nextRestartCount
|
||||
} else {
|
||||
log.debug(s"Terminating on restart #{} which exceeds max allowed restarts ({})", nextRestartCount, maxNrOfRetries)
|
||||
context.stop(self)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def receive: Receive = onTerminated orElse handleBackoff
|
||||
|
||||
protected def handleMessageToChild(msg: Any): Unit = child match {
|
||||
case Some(c) ⇒
|
||||
c.forward(msg)
|
||||
if (!finalStopMessageReceived) finalStopMessage match {
|
||||
case Some(fsm) ⇒ finalStopMessageReceived = fsm(msg)
|
||||
case None ⇒
|
||||
}
|
||||
case None ⇒
|
||||
replyWhileStopped match {
|
||||
case Some(r) ⇒ sender() ! r
|
||||
case None ⇒ context.system.deadLetters.forward(msg)
|
||||
}
|
||||
finalStopMessage match {
|
||||
case Some(fsm) if fsm(msg) ⇒ context.stop(self)
|
||||
case _ ⇒
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -207,6 +207,26 @@ 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.
|
||||
|
||||
<a id="supervision-strategies"></a>
|
||||
#### 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 +259,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.
|
||||
* `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`:
|
||||
* `withDefaultStoppingStrategy`: Sets a `OneForOneStrategy` with the stopping decider that stops the child on all exceptions.
|
||||
* `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 }
|
||||
|
||||
|
|
|
|||
|
|
@ -466,6 +466,8 @@ Scala
|
|||
Java
|
||||
: @@snip [LambdaPersistenceDocTest.java](/akka-docs/src/test/java/jdocs/persistence/LambdaPersistenceDocTest.java) { #backoff }
|
||||
|
||||
See @ref:[Supervision strategies](general/supervision.md#supervision-strategies) for more details about actor supervision.
|
||||
|
||||
If persistence of an event is rejected before it is stored, e.g. due to serialization error,
|
||||
`onPersistRejected` will be invoked (logging a warning by default), and the actor continues with
|
||||
next message.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ package jdocs.persistence;
|
|||
|
||||
import akka.actor.*;
|
||||
import akka.japi.Procedure;
|
||||
import akka.pattern.BackoffOpts;
|
||||
import akka.pattern.BackoffSupervisor;
|
||||
import akka.persistence.*;
|
||||
import java.time.Duration;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
|
||||
public class LambdaPersistenceDocTest {
|
||||
|
|
@ -20,6 +21,7 @@ public class LambdaPersistenceDocTest {
|
|||
public interface PersistentActorMethods {
|
||||
// #persistence-id
|
||||
public String persistenceId();
|
||||
|
||||
// #persistence-id
|
||||
// #recovery-status
|
||||
public boolean recoveryRunning();
|
||||
|
|
@ -136,7 +138,8 @@ public class LambdaPersistenceDocTest {
|
|||
final Props childProps = Props.create(MyPersistentActor1.class);
|
||||
final Props props =
|
||||
BackoffSupervisor.props(
|
||||
childProps, "myActor", Duration.ofSeconds(3), Duration.ofSeconds(30), 0.2);
|
||||
BackoffOpts.onStop(
|
||||
childProps, "myActor", Duration.ofSeconds(3), Duration.ofSeconds(30), 0.2));
|
||||
getContext().actorOf(props, "mySupervisor");
|
||||
super.preStart();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
package docs.pattern
|
||||
|
||||
import akka.actor.{ ActorSystem, Props, OneForOneStrategy, SupervisorStrategy }
|
||||
import akka.pattern.{ Backoff, BackoffSupervisor }
|
||||
import akka.actor.{ ActorContext, ActorSystem, OneForOneStrategy, Props, SupervisorStrategy }
|
||||
import akka.cluster.sharding.ShardRegion.Passivate
|
||||
import akka.pattern.{ BackoffOpts, BackoffSupervisor }
|
||||
import akka.testkit.TestActors.EchoActor
|
||||
|
||||
class BackoffSupervisorDocSpec {
|
||||
|
|
@ -18,13 +19,12 @@ class BackoffSupervisorDocSpec {
|
|||
val childProps = Props(classOf[EchoActor])
|
||||
|
||||
val supervisor = BackoffSupervisor.props(
|
||||
Backoff.onStop(
|
||||
BackoffOpts.onStop(
|
||||
childProps,
|
||||
childName = "myEcho",
|
||||
minBackoff = 3.seconds,
|
||||
maxBackoff = 30.seconds,
|
||||
randomFactor = 0.2, // adds 20% "noise" to vary the intervals slightly
|
||||
maxNrOfRetries = -1
|
||||
randomFactor = 0.2 // adds 20% "noise" to vary the intervals slightly
|
||||
))
|
||||
|
||||
system.actorOf(supervisor, name = "echoSupervisor")
|
||||
|
|
@ -39,13 +39,12 @@ class BackoffSupervisorDocSpec {
|
|||
val childProps = Props(classOf[EchoActor])
|
||||
|
||||
val supervisor = BackoffSupervisor.props(
|
||||
Backoff.onFailure(
|
||||
BackoffOpts.onFailure(
|
||||
childProps,
|
||||
childName = "myEcho",
|
||||
minBackoff = 3.seconds,
|
||||
maxBackoff = 30.seconds,
|
||||
randomFactor = 0.2, // adds 20% "noise" to vary the intervals slightly
|
||||
maxNrOfRetries = -1
|
||||
randomFactor = 0.2 // adds 20% "noise" to vary the intervals slightly
|
||||
))
|
||||
|
||||
system.actorOf(supervisor, name = "echoSupervisor")
|
||||
|
|
@ -60,13 +59,12 @@ class BackoffSupervisorDocSpec {
|
|||
|
||||
//#backoff-custom-stop
|
||||
val supervisor = BackoffSupervisor.props(
|
||||
Backoff.onStop(
|
||||
BackoffOpts.onStop(
|
||||
childProps,
|
||||
childName = "myEcho",
|
||||
minBackoff = 3.seconds,
|
||||
maxBackoff = 30.seconds,
|
||||
randomFactor = 0.2, // adds 20% "noise" to vary the intervals slightly
|
||||
maxNrOfRetries = -1
|
||||
randomFactor = 0.2 // adds 20% "noise" to vary the intervals slightly
|
||||
).withManualReset // the child must send BackoffSupervisor.Reset to its parent
|
||||
.withDefaultStoppingStrategy // Stop at any Exception thrown
|
||||
)
|
||||
|
|
@ -83,13 +81,12 @@ class BackoffSupervisorDocSpec {
|
|||
|
||||
//#backoff-custom-fail
|
||||
val supervisor = BackoffSupervisor.props(
|
||||
Backoff.onFailure(
|
||||
BackoffOpts.onFailure(
|
||||
childProps,
|
||||
childName = "myEcho",
|
||||
minBackoff = 3.seconds,
|
||||
maxBackoff = 30.seconds,
|
||||
randomFactor = 0.2, // adds 20% "noise" to vary the intervals slightly
|
||||
maxNrOfRetries = -1
|
||||
randomFactor = 0.2 // adds 20% "noise" to vary the intervals slightly
|
||||
).withAutoReset(10.seconds) // reset if the child does not throw any errors within 10 seconds
|
||||
.withSupervisorStrategy(
|
||||
OneForOneStrategy() {
|
||||
|
|
@ -103,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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
package docs.persistence
|
||||
|
||||
import akka.actor._
|
||||
import akka.pattern.{ Backoff, BackoffSupervisor }
|
||||
import akka.pattern.{ Backoff, BackoffOpts, BackoffSupervisor }
|
||||
import akka.persistence._
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.scaladsl.{ Source, Sink, Flow }
|
||||
import akka.stream.scaladsl.{ Flow, Sink, Source }
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scala.language.postfixOps
|
||||
|
|
@ -96,15 +96,14 @@ object PersistenceDocSpec {
|
|||
abstract class MyActor extends Actor {
|
||||
import PersistAsync.MyPersistentActor
|
||||
//#backoff
|
||||
val childProps = Props[MyPersistentActor]
|
||||
val childProps = Props[MyPersistentActor]()
|
||||
val props = BackoffSupervisor.props(
|
||||
Backoff.onStop(
|
||||
BackoffOpts.onStop(
|
||||
childProps,
|
||||
childName = "myActor",
|
||||
minBackoff = 3.seconds,
|
||||
maxBackoff = 30.seconds,
|
||||
randomFactor = 0.2,
|
||||
maxNrOfRetries = -1))
|
||||
randomFactor = 0.2))
|
||||
context.actorOf(props, name = "mySupervisor")
|
||||
//#backoff
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue