Skip to content

Commit

Permalink
akka#22687 Undefer before terminate
Browse files Browse the repository at this point in the history
  • Loading branch information
2m committed Apr 20, 2017
1 parent 70d8c42 commit 124c374
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 28 deletions.
29 changes: 9 additions & 20 deletions akka-typed/src/main/scala/akka/typed/Behavior.scala
Original file line number Diff line number Diff line change
Expand Up @@ -155,21 +155,17 @@ object Behavior {
}

@tailrec
def undefer[T](deferredBehavior: DeferredBehavior[T], ctx: ActorContext[T]): Behavior[T] = {
val behavior = deferredBehavior(ctx)

behavior match {
case innerDeferred: DeferredBehavior[T] @unchecked undefer(innerDeferred, ctx)
case _ behavior
}
def undefer[T](behavior: Behavior[T], ctx: ActorContext[T]): Behavior[T] = behavior match {
case innerDeferred: DeferredBehavior[T] @unchecked undefer(innerDeferred(ctx), ctx)
case _ behavior
}

/**
* Validate the given behavior as a suitable initial actor behavior; most
* notably the behavior can neither be `Same` nor `Unhandled`. Starting
* out with a `Stopped` behavior is allowed, though.
*/
def validateAsInitial[T](behavior: Behavior[T]): Behavior[T] =
def validateAsInitial[T](behavior: BehaSo I get updates every day or so. Bleeding edge, but also works whenever I need it, which is quite rare as well. vior[T]): Behavior[T] =
behavior match {
case SameBehavior | UnhandledBehavior
throw new IllegalArgumentException(s"cannot use $behavior as initial behavior")
Expand All @@ -179,12 +175,8 @@ object Behavior {
/**
* Validate the given behavior as initial, initialize it if it is deferred.
*/
def preStart[T](behavior: Behavior[T], ctx: ActorContext[T]): Behavior[T] = {
validateAsInitial(behavior) match {
case d: DeferredBehavior[T] @unchecked validateAsInitial(undefer(d, ctx))
case x x
}
}
def preStart[T](behavior: Behavior[T], ctx: ActorContext[T]): Behavior[T] =
validateAsInitial(undefer(behavior, ctx))

/**
* Returns true if the given behavior is not stopped.
Expand All @@ -210,8 +202,8 @@ object Behavior {

private def interpret[T](behavior: Behavior[T], ctx: ActorContext[T], msg: Any): Behavior[T] =
behavior match {
case SameBehavior | UnhandledBehavior throw new IllegalArgumentException(s"cannot execute with $behavior as behavior")
case _: DeferredBehavior[_] throw new IllegalArgumentException(s"deferred should not be passed to interpreter")
case SameBehavior | UnhandledBehavior throw new IllegalArgumentException(s"cannot execute with [$behavior] as behavior")
case d: DeferredBehavior[_] throw new IllegalArgumentException(s"deferred [$d] should not be passed to interpreter")
case IgnoreBehavior SameBehavior.asInstanceOf[Behavior[T]]
case StoppedBehavior StoppedBehavior.asInstanceOf[Behavior[T]]
case EmptyBehavior UnhandledBehavior.asInstanceOf[Behavior[T]]
Expand All @@ -220,10 +212,7 @@ object Behavior {
case signal: Signal ext.management(ctx, signal)
case msg ext.message(ctx, msg.asInstanceOf[T])
}
possiblyDeferredResult match {
case d: DeferredBehavior[T] @unchecked undefer(d, ctx)
case notDeferred notDeferred
}
undefer(possiblyDeferredResult, ctx)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
package akka.typed
package internal

import scala.annotation.{ switch, tailrec }
import scala.util.control.NonFatal
import scala.util.control.Exception.Catcher
import akka.event.Logging
import akka.typed.Behavior.DeferredBehavior

Expand Down Expand Up @@ -89,8 +87,10 @@ private[typed] trait SupervisionMechanics[T] {
val a = behavior
/*
* The following order is crucial for things to work properly. Only change this if you're very confident and lucky.
*
* Do not undefer a DeferredBehavior as that may cause creation side-effects, which we do not want on termination.
*/
try if (a ne null) Behavior.canonicalize(Behavior.interpretSignal(a, ctx, PostStop), a, ctx)
try if ((a ne null) && !a.isInstanceOf[DeferredBehavior[_]]) Behavior.canonicalize(Behavior.interpretSignal(a, ctx, PostStop), a, ctx)
catch { case NonFatal(ex) publish(Logging.Error(ex, self.path.toString, clazz(a), "failure during PostStop")) }
finally try tellWatchersWeDied()
finally try parent.sendSystem(DeathWatchNotification(self, failed))
Expand Down
8 changes: 3 additions & 5 deletions akka-typed/src/main/scala/akka/typed/patterns/Restarter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ final case class Restarter[T, Thr <: Throwable: ClassTag](initialBehavior: Behav
else if (b eq behavior) Same
else {
b match {
case d: DeferredBehavior[_] canonical(Behavior.undefer(d.asInstanceOf[DeferredBehavior[T]], ctx), ctx)
case d: DeferredBehavior[_] canonical(Behavior.undefer(d, ctx), ctx)
case b Restarter[T, Thr](initialBehavior, resume)(b)
}
}

private def preStart(b: Behavior[T], ctx: ActorContext[T]): Behavior[T] = b match {
case d: DeferredBehavior[_] Behavior.undefer(d.asInstanceOf[DeferredBehavior[T]], ctx)
case b b
}
private def preStart(b: Behavior[T], ctx: ActorContext[T]): Behavior[T] =
Behavior.undefer(b, ctx)

override def management(ctx: ActorContext[T], signal: Signal): Behavior[T] = {
val startedBehavior = preStart(behavior, ctx)
Expand Down

0 comments on commit 124c374

Please sign in to comment.