diff --git a/akka-contrib/docs/cluster-singleton.rst b/akka-contrib/docs/cluster-singleton.rst index 1bed5a29e1..f1a81b93f0 100644 --- a/akka-contrib/docs/cluster-singleton.rst +++ b/akka-contrib/docs/cluster-singleton.rst @@ -71,6 +71,12 @@ In Java: .. includecode:: @contribSrc@/src/test/java/akka/contrib/pattern/ClusterSingletonManagerTest.java#create-singleton-manager +.. note:: + + The ``singletonProps``/``singletonPropsFactory`` is invoked when creating + the singleton actor and it must not use members that are not thread safe, e.g. + mutable state in enclosing actor. + Here we use an application specific ``terminationMessage`` to be able to close the resources before actually stopping the singleton actor. Note that ``PoisonPill`` is a perfectly fine ``terminationMessage`` if you only need to stop the actor. diff --git a/akka-contrib/src/main/scala/akka/contrib/pattern/ClusterSingletonManager.scala b/akka-contrib/src/main/scala/akka/contrib/pattern/ClusterSingletonManager.scala index 33d45b376d..3fae5072e5 100644 --- a/akka-contrib/src/main/scala/akka/contrib/pattern/ClusterSingletonManager.scala +++ b/akka-contrib/src/main/scala/akka/contrib/pattern/ClusterSingletonManager.scala @@ -25,6 +25,9 @@ object ClusterSingletonManager { /** * Scala API: Factory method for `ClusterSingletonManager` [[akka.actor.Props]]. + * Note that the `singletonProps` function is applied when creating + * the singleton actor and it must not use members that are not thread safe, e.g. + * mutable state in enclosing actor. */ def props( singletonProps: Option[Any] ⇒ Props, @@ -39,6 +42,9 @@ object ClusterSingletonManager { /** * Java API: Factory method for `ClusterSingletonManager` [[akka.actor.Props]]. + * Note that the `singletonPropsFactory` is invoked when creating + * the singleton actor and it must not use members that are not thread safe, e.g. + * mutable state in enclosing actor. */ def props( singletonName: String, @@ -54,6 +60,9 @@ object ClusterSingletonManager { /** * Java API: Factory method for `ClusterSingletonManager` [[akka.actor.Props]] * with default values. + * Note that the `singletonPropsFactory` is invoked when creating + * the singleton actor and it must not use members that are not thread safe, e.g. + * mutable state in enclosing actor. */ def defaultProps( singletonName: String, @@ -325,7 +334,9 @@ class ClusterSingletonManagerIsStuck(message: String) extends AkkaException(mess * might be None when no hand-over took place, or when the there * is no need for sending data to the new singleton. The `handOverData` * is typically passed as parameter to the constructor of the - * singleton actor. + * singleton actor. Note that the `singletonProps` function is applied when creating + * the singleton actor and it must not use members that are not thread safe, e.g. + * mutable state in enclosing actor. * * '''''singletonName''''' The actor name of the child singleton actor. * diff --git a/akka-contrib/src/multi-jvm/scala/akka/contrib/pattern/ClusterSingletonManagerSpec.scala b/akka-contrib/src/multi-jvm/scala/akka/contrib/pattern/ClusterSingletonManagerSpec.scala index 9b2687bc34..048f81afd7 100644 --- a/akka-contrib/src/multi-jvm/scala/akka/contrib/pattern/ClusterSingletonManagerSpec.scala +++ b/akka-contrib/src/multi-jvm/scala/akka/contrib/pattern/ClusterSingletonManagerSpec.scala @@ -195,8 +195,11 @@ class ClusterSingletonManagerSpec extends MultiNodeSpec(ClusterSingletonManagerS val identifyProbe = TestProbe() + val controllerRootActorPath = node(controller) + def queue: ActorRef = { - system.actorSelection(node(controller) / "user" / "queue").tell(Identify("queue"), identifyProbe.ref) + // this is used from inside actor construction, i.e. other thread, and must therefore not call `node(controller` + system.actorSelection(controllerRootActorPath / "user" / "queue").tell(Identify("queue"), identifyProbe.ref) identifyProbe.expectMsgType[ActorIdentity].ref.get }