Merge pull request #1671 from akka/wip-3529-identify-sugar-patriknw
+act #3529 Add convenience helper for looking up an actor by identity
This commit is contained in:
commit
713478f963
9 changed files with 109 additions and 6 deletions
|
|
@ -61,6 +61,12 @@ class ActorSelectionSpec extends AkkaSpec("akka.loglevel=DEBUG") with DefaultTim
|
||||||
val asked = Await.result((selection ? Identify(selection)).mapTo[ActorIdentity], timeout.duration)
|
val asked = Await.result((selection ? Identify(selection)).mapTo[ActorIdentity], timeout.duration)
|
||||||
asked.ref must be(result)
|
asked.ref must be(result)
|
||||||
asked.correlationId must be(selection)
|
asked.correlationId must be(selection)
|
||||||
|
|
||||||
|
implicit val ec = system.dispatcher
|
||||||
|
val resolved = Await.result(selection.resolveOne(timeout.duration).mapTo[ActorRef] recover { case _ ⇒ null },
|
||||||
|
timeout.duration)
|
||||||
|
Option(resolved) must be(result)
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,6 +297,24 @@ class ActorSelectionSpec extends AkkaSpec("akka.loglevel=DEBUG") with DefaultTim
|
||||||
expectNoMsg(1 second)
|
expectNoMsg(1 second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"resolve one actor with explicit timeout" in {
|
||||||
|
val s = system.actorSelection(system / "c2")
|
||||||
|
// Java and Scala API
|
||||||
|
Await.result(s.resolveOne(1.second.dilated), timeout.duration) must be === c2
|
||||||
|
}
|
||||||
|
|
||||||
|
"resolve one actor with implicit timeout" in {
|
||||||
|
val s = system.actorSelection(system / "c2")
|
||||||
|
// Scala API; implicit timeout from DefaultTimeout trait
|
||||||
|
Await.result(s.resolveOne(), timeout.duration) must be === c2
|
||||||
|
}
|
||||||
|
|
||||||
|
"resolve non-existing with Failure" in {
|
||||||
|
intercept[ActorNotFound] {
|
||||||
|
Await.result(system.actorSelection(system / "none").resolveOne(1.second.dilated), timeout.duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"compare equally" in {
|
"compare equally" in {
|
||||||
ActorSelection(c21, "../*/hello") must be === ActorSelection(c21, "../*/hello")
|
ActorSelection(c21, "../*/hello") must be === ActorSelection(c21, "../*/hello")
|
||||||
ActorSelection(c21, "../*/hello").## must be === ActorSelection(c21, "../*/hello").##
|
ActorSelection(c21, "../*/hello").## must be === ActorSelection(c21, "../*/hello").##
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,19 @@
|
||||||
package akka.actor
|
package akka.actor
|
||||||
|
|
||||||
import language.implicitConversions
|
import language.implicitConversions
|
||||||
import scala.collection.immutable
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
import akka.util.Helpers
|
|
||||||
import akka.routing.MurmurHash
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
import scala.collection.immutable
|
||||||
|
import scala.concurrent.Future
|
||||||
|
import scala.concurrent.Promise
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import scala.util.Success
|
||||||
|
import scala.util.Failure
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
import akka.pattern.ask
|
||||||
|
import akka.routing.MurmurHash
|
||||||
|
import akka.util.Helpers
|
||||||
|
import akka.util.Timeout
|
||||||
|
import akka.dispatch.ExecutionContexts
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ActorSelection is a logical view of a section of an ActorSystem's tree of Actors,
|
* An ActorSelection is a logical view of a section of an ActorSystem's tree of Actors,
|
||||||
|
|
@ -40,6 +48,38 @@ abstract class ActorSelection extends Serializable {
|
||||||
anchor.tell(toMessage(msg, path, path.length - 1), sender)
|
anchor.tell(toMessage(msg, path, path.length - 1), sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the [[ActorRef]] matching this selection.
|
||||||
|
* The result is returned as a Future that is completed with the [[ActorRef]]
|
||||||
|
* if such an actor exists. It is completed with failure [[ActorNotFound]] if
|
||||||
|
* no such actor exists or the identification didn't complete within the
|
||||||
|
* supplied `timeout`.
|
||||||
|
*
|
||||||
|
* Under the hood it talks to the actor to verify its existence and acquire its
|
||||||
|
* [[ActorRef]].
|
||||||
|
*/
|
||||||
|
def resolveOne()(implicit timeout: Timeout): Future[ActorRef] = {
|
||||||
|
implicit val ec = ExecutionContexts.sameThreadExecutionContext
|
||||||
|
val p = Promise[ActorRef]()
|
||||||
|
this.ask(Identify(None)) onComplete {
|
||||||
|
case Success(ActorIdentity(_, Some(ref))) ⇒ p.success(ref)
|
||||||
|
case _ ⇒ p.failure(ActorNotFound(this))
|
||||||
|
}
|
||||||
|
p.future
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the [[ActorRef]] matching this selection.
|
||||||
|
* The result is returned as a Future that is completed with the [[ActorRef]]
|
||||||
|
* if such an actor exists. It is completed with failure [[ActorNotFound]] if
|
||||||
|
* no such actor exists or the identification didn't complete within the
|
||||||
|
* supplied `timeout`.
|
||||||
|
*
|
||||||
|
* Under the hood it talks to the actor to verify its existence and acquire its
|
||||||
|
* [[ActorRef]].
|
||||||
|
*/
|
||||||
|
def resolveOne(timeout: FiniteDuration): Future[ActorRef] = resolveOne()(timeout)
|
||||||
|
|
||||||
override def toString: String = {
|
override def toString: String = {
|
||||||
(new java.lang.StringBuilder).append("ActorSelection[").
|
(new java.lang.StringBuilder).append("ActorSelection[").
|
||||||
append(anchor.toString).
|
append(anchor.toString).
|
||||||
|
|
@ -107,3 +147,11 @@ trait ScalaActorSelection {
|
||||||
|
|
||||||
def !(msg: Any)(implicit sender: ActorRef = Actor.noSender) = tell(msg, sender)
|
def !(msg: Any)(implicit sender: ActorRef = Actor.noSender) = tell(msg, sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When [[ActorSelection#resolveOne]] can't identify the actor the
|
||||||
|
* `Future` is completed with this failure.
|
||||||
|
*/
|
||||||
|
@SerialVersionUID(1L)
|
||||||
|
case class ActorNotFound(selection: ActorSelection) extends RuntimeException("Actor not found for: " + selection)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,8 @@ object Patterns {
|
||||||
* Register an onComplete callback on this [[scala.concurrent.Future]] to send
|
* Register an onComplete callback on this [[scala.concurrent.Future]] to send
|
||||||
* the result to the given [[akka.actor.ActorRef]] or [[akka.actor.ActorSelection]].
|
* the result to the given [[akka.actor.ActorRef]] or [[akka.actor.ActorSelection]].
|
||||||
* Returns the original Future to allow method chaining.
|
* Returns the original Future to allow method chaining.
|
||||||
|
* If the future was completed with failure it is sent as a [[akka.actor.Status.Failure]]
|
||||||
|
* to the recipient.
|
||||||
*
|
*
|
||||||
* <b>Recommended usage example:</b>
|
* <b>Recommended usage example:</b>
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ trait PipeToSupport {
|
||||||
* pipe(someFuture) to nextActor
|
* pipe(someFuture) to nextActor
|
||||||
*
|
*
|
||||||
* }}}
|
* }}}
|
||||||
|
*
|
||||||
|
* The successful result of the future is sent as a message to the recipient, or
|
||||||
|
* the failure is sent in a [[akka.actor.Status.Failure]] to the recipient.
|
||||||
*/
|
*/
|
||||||
implicit def pipe[T](future: Future[T])(implicit executionContext: ExecutionContext): PipeableFuture[T] = new PipeableFuture(future)
|
implicit def pipe[T](future: Future[T])(implicit executionContext: ExecutionContext): PipeableFuture[T] = new PipeableFuture(future)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ To acquire an :class:`ActorRef` for an :class:`ActorSelection` you need to
|
||||||
send a message to the selection and use the ``getSender`` reference of the reply from
|
send a message to the selection and use the ``getSender`` reference of the reply from
|
||||||
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
||||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||||
|
:class:`ActorRef`. This can also be done with the ``resolveOne`` method of
|
||||||
|
the :class:`ActorSelection`, which returns a ``Future`` of the matching
|
||||||
:class:`ActorRef`.
|
:class:`ActorRef`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,9 @@ occupying it. ``ActorSelection`` cannot be watched for this reason. It is
|
||||||
possible to resolve the current incarnation's ``ActorRef`` living under the
|
possible to resolve the current incarnation's ``ActorRef`` living under the
|
||||||
path by sending an ``Identify`` message to the ``ActorSelection`` which
|
path by sending an ``Identify`` message to the ``ActorSelection`` which
|
||||||
will be replied to with an ``ActorIdentity`` containing the correct reference
|
will be replied to with an ``ActorIdentity`` containing the correct reference
|
||||||
(see :ref:`actorSelection-java`).
|
(see :ref:`actorSelection-java`). This can also be done with the ``resolveOne``
|
||||||
|
method of the :class:`ActorSelection`, which returns a ``Future`` of the matching
|
||||||
|
:class:`ActorRef`.
|
||||||
|
|
||||||
.. _deathwatch-java:
|
.. _deathwatch-java:
|
||||||
|
|
||||||
|
|
@ -433,6 +435,12 @@ of that reply is guaranteed, it still is a normal message.
|
||||||
.. includecode:: code/docs/actor/UntypedActorDocTest.java
|
.. includecode:: code/docs/actor/UntypedActorDocTest.java
|
||||||
:include: import-identify,identify
|
:include: import-identify,identify
|
||||||
|
|
||||||
|
You can also acquire an :class:`ActorRef` for an :class:`ActorSelection` with
|
||||||
|
the ``resolveOne`` method of the :class:`ActorSelection`. It returns a ``Future``
|
||||||
|
of the matching :class:`ActorRef` if such an actor exists. It is completed with
|
||||||
|
failure [[akka.actor.ActorNotFound]] if no such actor exists or the identification
|
||||||
|
didn't complete within the supplied `timeout`.
|
||||||
|
|
||||||
Remote actor addresses may also be looked up, if :ref:`remoting <remoting-java>` is enabled:
|
Remote actor addresses may also be looked up, if :ref:`remoting <remoting-java>` is enabled:
|
||||||
|
|
||||||
.. includecode:: code/docs/actor/UntypedActorDocTest.java#selection-remote
|
.. includecode:: code/docs/actor/UntypedActorDocTest.java#selection-remote
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,12 @@ the actor. There is a built-in ``Identify`` message that all Actors will underst
|
||||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||||
:class:`ActorRef`.
|
:class:`ActorRef`.
|
||||||
|
|
||||||
|
You can also acquire an :class:`ActorRef` for an :class:`ActorSelection` with
|
||||||
|
the ``resolveOne`` method of the :class:`ActorSelection`. It returns a ``Future``
|
||||||
|
of the matching :class:`ActorRef` if such an actor exists. It is completed with
|
||||||
|
failure [[akka.actor.ActorNotFound]] if no such actor exists or the identification
|
||||||
|
didn't complete within the supplied `timeout`.
|
||||||
|
|
||||||
Read more about ``actorSelection`` in :ref:`docs for Java <actorSelection-java>` or
|
Read more about ``actorSelection`` in :ref:`docs for Java <actorSelection-java>` or
|
||||||
:ref:`docs for Scala <actorSelection-scala>`.
|
:ref:`docs for Scala <actorSelection-scala>`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -369,7 +369,9 @@ occupying it. ``ActorSelection`` cannot be watched for this reason. It is
|
||||||
possible to resolve the current incarnation's ``ActorRef`` living under the
|
possible to resolve the current incarnation's ``ActorRef`` living under the
|
||||||
path by sending an ``Identify`` message to the ``ActorSelection`` which
|
path by sending an ``Identify`` message to the ``ActorSelection`` which
|
||||||
will be replied to with an ``ActorIdentity`` containing the correct reference
|
will be replied to with an ``ActorIdentity`` containing the correct reference
|
||||||
(see :ref:`actorSelection-scala`).
|
(see :ref:`actorSelection-scala`). This can also be done with the ``resolveOne``
|
||||||
|
method of the :class:`ActorSelection`, which returns a ``Future`` of the matching
|
||||||
|
:class:`ActorRef`.
|
||||||
|
|
||||||
.. _deathwatch-scala:
|
.. _deathwatch-scala:
|
||||||
|
|
||||||
|
|
@ -516,6 +518,12 @@ of that reply is guaranteed, it still is a normal message.
|
||||||
|
|
||||||
.. includecode:: code/docs/actor/ActorDocSpec.scala#identify
|
.. includecode:: code/docs/actor/ActorDocSpec.scala#identify
|
||||||
|
|
||||||
|
You can also acquire an :class:`ActorRef` for an :class:`ActorSelection` with
|
||||||
|
the ``resolveOne`` method of the :class:`ActorSelection`. It returns a ``Future``
|
||||||
|
of the matching :class:`ActorRef` if such an actor exists. It is completed with
|
||||||
|
failure [[akka.actor.ActorNotFound]] if no such actor exists or the identification
|
||||||
|
didn't complete within the supplied `timeout`.
|
||||||
|
|
||||||
Remote actor addresses may also be looked up, if :ref:`remoting <remoting-scala>` is enabled:
|
Remote actor addresses may also be looked up, if :ref:`remoting <remoting-scala>` is enabled:
|
||||||
|
|
||||||
.. includecode:: code/docs/actor/ActorDocSpec.scala#selection-remote
|
.. includecode:: code/docs/actor/ActorDocSpec.scala#selection-remote
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,8 @@ To acquire an :class:`ActorRef` for an :class:`ActorSelection` you need to
|
||||||
send a message to the selection and use the ``sender`` reference of the reply from
|
send a message to the selection and use the ``sender`` reference of the reply from
|
||||||
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
||||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||||
|
:class:`ActorRef`. This can also be done with the ``resolveOne`` method of
|
||||||
|
the :class:`ActorSelection`, which returns a ``Future`` of the matching
|
||||||
:class:`ActorRef`.
|
:class:`ActorRef`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue