Merge pull request #1277 from akka/wip-3074-deprecate-actorFor-patriknw
Deprecate actorFor in favor of ActorSelection, see #3074
This commit is contained in:
commit
c77cdeb86b
80 changed files with 1496 additions and 619 deletions
|
|
@ -95,14 +95,14 @@ What is the Difference Between Actor Reference and Path?
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
An actor reference designates a single actor and the life-cycle of the reference
|
||||
matches that actor’s life-cycle; an actor path represents a name which may or
|
||||
may not be inhabited by an actor and the path itself does not have a life-cycle,
|
||||
it never becomes invalid. You can create an actor path without creating an actor,
|
||||
but you cannot create an actor reference without creating corresponding actor.
|
||||
matches that actor’s life-cycle; an actor path represents a name which may or
|
||||
may not be inhabited by an actor and the path itself does not have a life-cycle,
|
||||
it never becomes invalid. You can create an actor path without creating an actor,
|
||||
but you cannot create an actor reference without creating corresponding actor.
|
||||
|
||||
.. note::
|
||||
|
||||
That definition does not hold for ``actorFor``, which is one of the reasons why
|
||||
That definition does not hold for ``actorFor``, which is one of the reasons why
|
||||
``actorFor`` is deprecated in favor of ``actorSelection``.
|
||||
|
||||
You can create an actor, terminate it, and then create a new actor with the same
|
||||
|
|
@ -194,34 +194,43 @@ Looking up Actors by Concrete Path
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In addition, actor references may be looked up using the
|
||||
:meth:`ActorSystem.actorFor` method, which returns a local or remote actor
|
||||
reference. The reference can be reused for communicating with said actor during
|
||||
the whole lifetime of the actor. In the case of a local actor reference, the
|
||||
named actor needs to exist before the lookup, or else the acquired reference
|
||||
will be an :class:`EmptyLocalActorRef`. This will be true even if an actor with
|
||||
that exact path is created after acquiring the actor reference. For remote actor
|
||||
references acquired with `actorFor` the behaviour is different and sending messages
|
||||
to such a reference will under the hood look up the actor by path on the remote
|
||||
system for every message send.
|
||||
:meth:`ActorSystem.actorSelection` method. The selection can be used for
|
||||
communicating with said actor and the actor corresponding to the selection
|
||||
is looked up when delivering each message.
|
||||
|
||||
To acquire an :class:`ActorRef` that is bound to the life-cycle of a specific actor
|
||||
you need to send a message, such as the built-in :class:`Identify` message, to the actor
|
||||
and use the ``sender`` reference of a reply from the actor.
|
||||
|
||||
.. note::
|
||||
|
||||
``actorFor`` is deprecated in favor of ``actorSelection`` because actor references
|
||||
acquired with ``actorFor`` behave differently for local and remote actors.
|
||||
In the case of a local actor reference, the named actor needs to exist before the
|
||||
lookup, or else the acquired reference will be an :class:`EmptyLocalActorRef`.
|
||||
This will be true even if an actor with that exact path is created after acquiring
|
||||
the actor reference. For remote actor references acquired with `actorFor` the
|
||||
behaviour is different and sending messages to such a reference will under the hood
|
||||
look up the actor by path on the remote system for every message send.
|
||||
|
||||
Absolute vs. Relative Paths
|
||||
```````````````````````````
|
||||
|
||||
In addition to :meth:`ActorSystem.actorFor` there is also
|
||||
:meth:`ActorContext.actorFor`, which is available inside any actor as
|
||||
``context.actorFor``. This yields an actor reference much like its twin on
|
||||
In addition to :meth:`ActorSystem.actorSelection` there is also
|
||||
:meth:`ActorContext.actorSelection`, which is available inside any actor as
|
||||
``context.actorSelection``. This yields an actor selection much like its twin on
|
||||
:class:`ActorSystem`, but instead of looking up the path starting from the root
|
||||
of the actor tree it starts out on the current actor. Path elements consisting
|
||||
of two dots (``".."``) may be used to access the parent actor. You can for
|
||||
example send a message to a specific sibling::
|
||||
|
||||
context.actorFor("../brother") ! msg
|
||||
context.actorSelection("../brother") ! msg
|
||||
|
||||
Absolute paths may of course also be looked up on `context` in the usual way, i.e.
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
context.actorFor("/user/serviceA") ! msg
|
||||
context.actorSelection("/user/serviceA") ! msg
|
||||
|
||||
will work as expected.
|
||||
|
||||
|
|
@ -249,10 +258,10 @@ extracting the sender references, and then watch all discovered concrete
|
|||
actors. This scheme of resolving a selection may be improved upon in a future
|
||||
release.
|
||||
|
||||
.. _actorOf-vs-actorFor:
|
||||
.. _actorOf-vs-actorSelection:
|
||||
|
||||
Summary: ``actorOf`` vs. ``actorFor``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Summary: ``actorOf`` vs. ``actorSelection`` vs. ``actorFor``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -263,8 +272,12 @@ Summary: ``actorOf`` vs. ``actorFor``
|
|||
child of the context on which this method is invoked (which may be any
|
||||
actor or actor system).
|
||||
|
||||
- ``actorFor`` only ever looks up an existing actor, i.e. does not create
|
||||
one.
|
||||
- ``actorSelection`` only ever looks up existing actors when messages are
|
||||
delivered, i.e. does not create actors, or verify existence of actors
|
||||
when the selection is created.
|
||||
|
||||
- ``actorFor`` (deprecated in favor of actorSelection) only ever looks up an
|
||||
existing actor, i.e. does not create one.
|
||||
|
||||
Actor Reference and Path Equality
|
||||
---------------------------------
|
||||
|
|
@ -273,13 +286,13 @@ Equality of ``ActorRef`` match the intention that an ``ActorRef`` corresponds to
|
|||
the target actor incarnation. Two actor references are compared equal when they have
|
||||
the same path and point to the same actor incarnation. A reference pointing to a
|
||||
terminated actor does not compare equal to a reference pointing to another (re-created)
|
||||
actor with the same path. Note that a restart of an actor caused by a failure still
|
||||
means that it is the same actor incarnation, i.e. a restart is not visible for the
|
||||
actor with the same path. Note that a restart of an actor caused by a failure still
|
||||
means that it is the same actor incarnation, i.e. a restart is not visible for the
|
||||
consumer of the ``ActorRef``.
|
||||
|
||||
Remote actor references acquired with ``actorFor`` do not include the full
|
||||
information about the underlying actor identity and therefore such references
|
||||
do not compare equal to references acquired with ``actorOf``, ``sender``,
|
||||
information about the underlying actor identity and therefore such references
|
||||
do not compare equal to references acquired with ``actorOf``, ``sender``,
|
||||
or ``context.self``. Because of this ``actorFor`` is deprecated in favor of
|
||||
``actorSelection``.
|
||||
|
||||
|
|
@ -297,7 +310,7 @@ While it is possible to create an actor at a later time with an identical
|
|||
path—simply due to it being impossible to enforce the opposite without keeping
|
||||
the set of all actors ever created available—this is not good practice: remote
|
||||
actor references acquired with ``actorFor`` which “died” suddenly start to work
|
||||
again, but without any guarantee of ordering between this transition and any
|
||||
again, but without any guarantee of ordering between this transition and any
|
||||
other event, hence the new inhabitant of the path may receive messages which were destined for the
|
||||
previous tenant.
|
||||
|
||||
|
|
|
|||
|
|
@ -176,12 +176,13 @@ public class TypedActorDocTestBase {
|
|||
|
||||
@Test public void proxyAnyActorRef() {
|
||||
try {
|
||||
final ActorRef actorRefToRemoteActor = system.deadLetters();
|
||||
//#typed-actor-remote
|
||||
Squarer typedActor =
|
||||
TypedActor.get(system).
|
||||
typedActorOf(
|
||||
new TypedProps<Squarer>(Squarer.class),
|
||||
system.actorFor("akka://SomeSystem@somehost:2552/user/some/foobar")
|
||||
actorRefToRemoteActor
|
||||
);
|
||||
//Use "typedActor" as a FooBar
|
||||
//#typed-actor-remote
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import akka.dispatch.Futures;
|
|||
import akka.dispatch.Mapper;
|
||||
import scala.concurrent.Await;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import akka.testkit.AkkaSpec;
|
||||
import akka.util.Timeout;
|
||||
//#import-future
|
||||
|
||||
|
|
@ -31,6 +32,12 @@ import akka.japi.Procedure;
|
|||
import akka.actor.Terminated;
|
||||
//#import-watch
|
||||
|
||||
//#import-identify
|
||||
import akka.actor.ActorSelection;
|
||||
import akka.actor.Identify;
|
||||
import akka.actor.ActorIdentity;
|
||||
//#import-identify
|
||||
|
||||
//#import-gracefulStop
|
||||
import static akka.pattern.Patterns.gracefulStop;
|
||||
import scala.concurrent.Future;
|
||||
|
|
@ -58,6 +65,8 @@ import akka.actor.UntypedActor;
|
|||
import akka.actor.UntypedActorFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import scala.Option;
|
||||
import java.lang.Object;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -65,6 +74,19 @@ import akka.pattern.Patterns;
|
|||
|
||||
public class UntypedActorDocTestBase {
|
||||
|
||||
private static ActorSystem system;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeAll() {
|
||||
system = ActorSystem.create("MySystem", AkkaSpec.testConf());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterAll() {
|
||||
system.shutdown();
|
||||
system = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createProps() {
|
||||
//#creating-props-config
|
||||
|
|
@ -96,86 +118,71 @@ public class UntypedActorDocTestBase {
|
|||
@Test
|
||||
public void contextActorOf() {
|
||||
//#context-actorOf
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef myActor = system.actorOf(new Props(MyUntypedActor.class), "myactor");
|
||||
ActorRef myActor = system.actorOf(new Props(MyUntypedActor.class), "myactor2");
|
||||
//#context-actorOf
|
||||
myActor.tell("test", null);
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorActorOf() {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
//#creating-constructor
|
||||
// allows passing in arguments to the MyActor constructor
|
||||
ActorRef myActor = system.actorOf(new Props(new UntypedActorFactory() {
|
||||
public UntypedActor create() {
|
||||
return new MyActor("...");
|
||||
}
|
||||
}), "myactor");
|
||||
}), "myactor3");
|
||||
//#creating-constructor
|
||||
myActor.tell("test", null);
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propsActorOf() {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
//#creating-props
|
||||
ActorRef myActor = system.actorOf(
|
||||
new Props(MyUntypedActor.class).withDispatcher("my-dispatcher"), "myactor");
|
||||
new Props(MyUntypedActor.class).withDispatcher("my-dispatcher"), "myactor4");
|
||||
//#creating-props
|
||||
myActor.tell("test", null);
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usingAsk() throws Exception {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef myActor = system.actorOf(new Props(new UntypedActorFactory() {
|
||||
public UntypedActor create() {
|
||||
return new MyAskActor();
|
||||
}
|
||||
}), "myactor");
|
||||
}), "myactor5");
|
||||
|
||||
//#using-ask
|
||||
Future<Object> future = Patterns.ask(myActor, "Hello", 1000);
|
||||
Object result = Await.result(future, Duration.create(1, TimeUnit.SECONDS));
|
||||
//#using-ask
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiveTimeout() {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef myActor = system.actorOf(new Props(MyReceivedTimeoutUntypedActor.class));
|
||||
myActor.tell("Hello", null);
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usePoisonPill() {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef myActor = system.actorOf(new Props(MyUntypedActor.class));
|
||||
//#poison-pill
|
||||
myActor.tell(PoisonPill.getInstance(), null);
|
||||
//#poison-pill
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useKill() {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef victim = system.actorOf(new Props(MyUntypedActor.class));
|
||||
//#kill
|
||||
victim.tell(Kill.getInstance(), null);
|
||||
//#kill
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useBecome() {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef myActor = system.actorOf(new Props(new UntypedActorFactory() {
|
||||
public UntypedActor create() {
|
||||
return new HotSwapActor();
|
||||
|
|
@ -184,21 +191,24 @@ public class UntypedActorDocTestBase {
|
|||
myActor.tell("foo", null);
|
||||
myActor.tell("bar", null);
|
||||
myActor.tell("bar", null);
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useWatch() throws Exception {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef myActor = system.actorOf(new Props(WatchActor.class));
|
||||
Future<Object> future = Patterns.ask(myActor, "kill", 1000);
|
||||
assert Await.result(future, Duration.create("1 second")).equals("finished");
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useIdentify() throws Exception {
|
||||
ActorRef a = system.actorOf(new Props(MyUntypedActor.class), "another");
|
||||
ActorRef b = system.actorOf(new Props(Follower.class));
|
||||
system.stop(a);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usePatternsGracefulStop() throws Exception {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef actorRef = system.actorOf(new Props(MyUntypedActor.class));
|
||||
//#gracefulStop
|
||||
try {
|
||||
|
|
@ -210,7 +220,6 @@ public class UntypedActorDocTestBase {
|
|||
// the actor wasn't stopped within 5 seconds
|
||||
}
|
||||
//#gracefulStop
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
class Result {
|
||||
|
|
@ -225,7 +234,6 @@ public class UntypedActorDocTestBase {
|
|||
|
||||
@Test
|
||||
public void usePatternsAskPipe() {
|
||||
ActorSystem system = ActorSystem.create("MySystem");
|
||||
ActorRef actorA = system.actorOf(new Props(MyUntypedActor.class));
|
||||
ActorRef actorB = system.actorOf(new Props(MyUntypedActor.class));
|
||||
ActorRef actorC = system.actorOf(new Props(MyUntypedActor.class));
|
||||
|
|
@ -251,7 +259,6 @@ public class UntypedActorDocTestBase {
|
|||
|
||||
pipe(transformed, system.dispatcher()).to(actorC);
|
||||
//#ask-pipe
|
||||
system.shutdown();
|
||||
}
|
||||
|
||||
public static class MyActor extends UntypedActor {
|
||||
|
|
@ -399,4 +406,40 @@ public class UntypedActorDocTestBase {
|
|||
}
|
||||
//#watch
|
||||
|
||||
static
|
||||
//#identify
|
||||
public class Follower extends UntypedActor {
|
||||
String identifyId = "1";
|
||||
{
|
||||
ActorSelection selection =
|
||||
getContext().actorSelection("/user/another");
|
||||
selection.tell(new Identify(identifyId), getSelf());
|
||||
}
|
||||
ActorRef another;
|
||||
|
||||
@Override
|
||||
public void onReceive(Object message) {
|
||||
if (message instanceof ActorIdentity) {
|
||||
ActorIdentity identity = (ActorIdentity) message;
|
||||
if (identity.correlationId().equals(identifyId)) {
|
||||
ActorRef ref = identity.getRef();
|
||||
if (ref == null)
|
||||
getContext().stop(getSelf());
|
||||
else {
|
||||
another = ref;
|
||||
getContext().watch(another);
|
||||
}
|
||||
}
|
||||
} else if (message instanceof Terminated) {
|
||||
final Terminated t = (Terminated) message;
|
||||
if (t.getActor().equals(another)) {
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
//#identify
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,10 @@ public class SerializationDocTestBase {
|
|||
//#my-own-serializer
|
||||
|
||||
@Test public void serializeActorRefs() {
|
||||
final ActorSystem theActorSystem =
|
||||
final ExtendedActorSystem extendedSystem = (ExtendedActorSystem)
|
||||
ActorSystem.create("whatever");
|
||||
final ActorRef theActorRef =
|
||||
theActorSystem.deadLetters(); // Of course this should be you
|
||||
extendedSystem.deadLetters(); // Of course this should be you
|
||||
|
||||
//#actorref-serializer
|
||||
// Serialize
|
||||
|
|
@ -63,10 +63,10 @@ public class SerializationDocTestBase {
|
|||
|
||||
// Deserialize
|
||||
// (beneath fromBinary)
|
||||
final ActorRef deserializedActorRef = theActorSystem.actorFor(identifier);
|
||||
final ActorRef deserializedActorRef = extendedSystem.provider().resolveActorRef(identifier);
|
||||
// Then just use the ActorRef
|
||||
//#actorref-serializer
|
||||
theActorSystem.shutdown();
|
||||
extendedSystem.shutdown();
|
||||
}
|
||||
|
||||
static
|
||||
|
|
@ -150,7 +150,7 @@ public class SerializationDocTestBase {
|
|||
return new DefaultAddressExt(system);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#external-address-default
|
||||
|
||||
public void demonstrateDefaultAddress() {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import akka.actor.ActorKilledException;
|
|||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Kill;
|
||||
import akka.actor.PoisonPill;
|
||||
import akka.actor.Props;
|
||||
import akka.actor.Terminated;
|
||||
import akka.actor.UntypedActor;
|
||||
|
|
@ -30,7 +31,7 @@ import akka.testkit.JavaTestKit;
|
|||
import scala.concurrent.duration.Duration;
|
||||
|
||||
public class TestKitDocTest {
|
||||
|
||||
|
||||
//#test-actor-ref
|
||||
static class MyActor extends UntypedActor {
|
||||
public void onReceive(Object o) throws Exception {
|
||||
|
|
@ -42,18 +43,18 @@ public class TestKitDocTest {
|
|||
}
|
||||
public boolean testMe() { return true; }
|
||||
}
|
||||
|
||||
|
||||
//#test-actor-ref
|
||||
|
||||
|
||||
private static ActorSystem system;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
final Config config = ConfigFactory.parseString(
|
||||
"akka.loggers = [akka.testkit.TestEventListener]");
|
||||
system = ActorSystem.create("demoSystem", config);
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void cleanup() {
|
||||
system.shutdown();
|
||||
|
|
@ -68,7 +69,7 @@ public class TestKitDocTest {
|
|||
assertTrue(actor.testMe());
|
||||
}
|
||||
//#test-actor-ref
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateAsk() throws Exception {
|
||||
//#test-behavior
|
||||
|
|
@ -79,7 +80,7 @@ public class TestKitDocTest {
|
|||
assertEquals(42, Await.result(future, Duration.Zero()));
|
||||
//#test-behavior
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateExceptions() {
|
||||
//#test-expecting-exceptions
|
||||
|
|
@ -93,7 +94,7 @@ public class TestKitDocTest {
|
|||
}
|
||||
//#test-expecting-exceptions
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateWithin() {
|
||||
//#test-within
|
||||
|
|
@ -108,7 +109,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-within
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateExpectMsg() {
|
||||
//#test-expectmsg
|
||||
|
|
@ -128,7 +129,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-expectmsg
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateReceiveWhile() {
|
||||
//#test-receivewhile
|
||||
|
|
@ -136,7 +137,7 @@ public class TestKitDocTest {
|
|||
getRef().tell(42, null);
|
||||
getRef().tell(43, null);
|
||||
getRef().tell("hello", null);
|
||||
final String[] out =
|
||||
final String[] out =
|
||||
new ReceiveWhile<String>(String.class, duration("1 second")) {
|
||||
// do not put code outside this method, will run afterwards
|
||||
protected String match(Object in) {
|
||||
|
|
@ -168,7 +169,7 @@ public class TestKitDocTest {
|
|||
//#test-receivewhile-full
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateAwaitCond() {
|
||||
//#test-awaitCond
|
||||
|
|
@ -205,7 +206,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-awaitAssert
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked") // due to generic varargs
|
||||
public void demonstrateExpect() {
|
||||
|
|
@ -236,7 +237,7 @@ public class TestKitDocTest {
|
|||
assertArrayEquals(new String[] {"hello", "world"}, all);
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateIgnoreMsg() {
|
||||
//#test-ignoreMsg
|
||||
|
|
@ -268,7 +269,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#duration-dilation
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateProbe() {
|
||||
//#test-probe
|
||||
|
|
@ -282,11 +283,11 @@ public class TestKitDocTest {
|
|||
target.forward(msg, getContext());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
new JavaTestKit(system) {{
|
||||
// create a test probe
|
||||
final JavaTestKit probe = new JavaTestKit(system);
|
||||
|
||||
|
||||
// create a forwarder, injecting the probe’s testActor
|
||||
final Props props = new Props(new UntypedActorFactory() {
|
||||
private static final long serialVersionUID = 8927158735963950216L;
|
||||
|
|
@ -295,7 +296,7 @@ public class TestKitDocTest {
|
|||
}
|
||||
});
|
||||
final ActorRef forwarder = system.actorOf(props, "forwarder");
|
||||
|
||||
|
||||
// verify correct forwarding
|
||||
forwarder.tell(42, getRef());
|
||||
probe.expectMsgEquals(42);
|
||||
|
|
@ -303,7 +304,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-probe
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateSpecialProbe() {
|
||||
//#test-special-probe
|
||||
|
|
@ -323,20 +324,21 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-special-probe
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateWatch() {
|
||||
final ActorRef target = system.actorFor("/buh");
|
||||
final ActorRef target = system.actorOf(new Props(MyActor.class));
|
||||
//#test-probe-watch
|
||||
new JavaTestKit(system) {{
|
||||
final JavaTestKit probe = new JavaTestKit(system);
|
||||
probe.watch(target);
|
||||
target.tell(PoisonPill.getInstance(), null);
|
||||
final Terminated msg = probe.expectMsgClass(Terminated.class);
|
||||
assertEquals(msg.getActor(), target);
|
||||
}};
|
||||
//#test-probe-watch
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateReply() {
|
||||
//#test-probe-reply
|
||||
|
|
@ -350,7 +352,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-probe-reply
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateForward() {
|
||||
//#test-probe-forward
|
||||
|
|
@ -364,7 +366,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-probe-forward
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateWithinProbe() {
|
||||
try {
|
||||
|
|
@ -382,7 +384,7 @@ public class TestKitDocTest {
|
|||
// expected to fail
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateAutoPilot() {
|
||||
//#test-auto-pilot
|
||||
|
|
@ -404,7 +406,7 @@ public class TestKitDocTest {
|
|||
}};
|
||||
//#test-auto-pilot
|
||||
}
|
||||
|
||||
|
||||
// only compilation
|
||||
public void demonstrateCTD() {
|
||||
//#calling-thread-dispatcher
|
||||
|
|
@ -413,24 +415,24 @@ public class TestKitDocTest {
|
|||
.withDispatcher(CallingThreadDispatcher.Id()));
|
||||
//#calling-thread-dispatcher
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void demonstrateEventFilter() {
|
||||
//#test-event-filter
|
||||
new JavaTestKit(system) {{
|
||||
assertEquals("demoSystem", system.name());
|
||||
final ActorRef victim = system.actorOf(Props.empty(), "victim");
|
||||
|
||||
|
||||
final int result = new EventFilter<Integer>(ActorKilledException.class) {
|
||||
protected Integer run() {
|
||||
victim.tell(Kill.getInstance(), null);
|
||||
return 42;
|
||||
}
|
||||
}.from("akka://demoSystem/user/victim").occurrences(1).exec();
|
||||
|
||||
|
||||
assertEquals(42, result);
|
||||
}};
|
||||
//#test-event-filter
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,17 +70,24 @@ reference file for more information:
|
|||
Looking up Remote Actors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``actorFor(path)`` will obtain an ``ActorRef`` to an Actor on a remote node::
|
||||
``actorSelection(path)`` will obtain an ``ActorSelection`` to an Actor on a remote node::
|
||||
|
||||
ActorRef actor = context.actorFor("akka.tcp://app@10.0.0.1:2552/user/serviceA/worker");
|
||||
ActorSelection selection =
|
||||
context.actorSelection("akka.tcp://app@10.0.0.1:2552/user/serviceA/worker");
|
||||
|
||||
As you can see from the example above the following pattern is used to find an ``ActorRef`` on a remote node::
|
||||
As you can see from the example above the following pattern is used to find an actor on a remote node::
|
||||
|
||||
akka.<protocol>://<actorsystemname>@<hostname>:<port>/<actor path>
|
||||
|
||||
Once you obtained a reference to the actor you can interact with it they same way you would with a local actor, e.g.::
|
||||
Once you obtained a selection to the actor you can interact with it they same way you would with a local actor, e.g.::
|
||||
|
||||
actor.tell("Pretty awesome feature", getSelf());
|
||||
selection.tell("Pretty awesome feature", getSelf());
|
||||
|
||||
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
|
||||
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||
:class:`ActorRef`.
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -264,9 +271,9 @@ and it is created from an actor system using the aforementioned client’s confi
|
|||
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JLookupApplication.java
|
||||
:include: setup
|
||||
|
||||
Requests which come in via ``doSomething`` will be sent to the client actor
|
||||
along with the reference which was looked up earlier. Observe how the actor
|
||||
system name using in ``actorFor`` matches the remote system’s name, as do IP
|
||||
Requests which come in via ``doSomething`` will be sent to the client actor,
|
||||
which will use the actor reference that was identified earlier. Observe how the actor
|
||||
system name using in ``actorSelection`` matches the remote system’s name, as do IP
|
||||
and port number. Top-level actors are always created below the ``"/user"``
|
||||
guardian, which supervises them.
|
||||
|
||||
|
|
@ -481,14 +488,14 @@ SSL can be used as the remote transport by adding ``akka.remote.netty.ssl``
|
|||
to the ``enabled-transport`` configuration section. See a description of the settings
|
||||
in the :ref:`remoting-java-configuration` section.
|
||||
|
||||
The SSL support is implemented with Java Secure Socket Extension, please consult the offical
|
||||
The SSL support is implemented with Java Secure Socket Extension, please consult the offical
|
||||
`Java Secure Socket Extension documentation <http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html>`_
|
||||
and related resources for troubleshooting.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
When using SHA1PRNG on Linux it's recommended specify ``-Djava.security.egd=file:/dev/./urandom`` as argument
|
||||
When using SHA1PRNG on Linux it's recommended specify ``-Djava.security.egd=file:/dev/./urandom`` as argument
|
||||
to the JVM to prevent blocking. It is NOT as secure because it reuses the seed.
|
||||
Use '/dev/./urandom', not '/dev/urandom' as that doesn't work according to
|
||||
Use '/dev/./urandom', not '/dev/urandom' as that doesn't work according to
|
||||
`Bug ID: 6202721 <http://bugs.sun.com/view_bug.do?bug_id=6202721>`_.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -206,11 +206,11 @@ Proxying
|
|||
--------
|
||||
|
||||
You can use the ``typedActorOf`` that takes a TypedProps and an ActorRef to proxy the given ActorRef as a TypedActor.
|
||||
This is usable if you want to communicate remotely with TypedActors on other machines, just look them up with ``actorFor`` and pass the ``ActorRef`` to ``typedActorOf``.
|
||||
This is usable if you want to communicate remotely with TypedActors on other machines, just pass the ``ActorRef`` to ``typedActorOf``.
|
||||
|
||||
Lookup & Remoting
|
||||
-----------------
|
||||
|
||||
Since ``TypedActors`` are backed by ``Akka Actors``, you can use ``actorFor`` together with ``typedActorOf`` to proxy ``ActorRefs`` potentially residing on remote nodes.
|
||||
Since ``TypedActors`` are backed by ``Akka Actors``, you can use ``typedActorOf`` to proxy ``ActorRefs`` potentially residing on remote nodes.
|
||||
|
||||
.. includecode:: code/docs/actor/TypedActorDocTestBase.java#typed-actor-remote
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ Creating Actors
|
|||
Since Akka enforces parental supervision every actor is supervised and
|
||||
(potentially) the supervisor of its children, it is advisable that you
|
||||
familiarize yourself with :ref:`actor-systems` and :ref:`supervision` and it
|
||||
may also help to read :ref:`actorOf-vs-actorFor` (the whole of
|
||||
:ref:`addressing` is recommended reading in any case).
|
||||
may also help to read :ref:`addressing`.
|
||||
|
||||
Defining an Actor class
|
||||
-----------------------
|
||||
|
|
@ -130,7 +129,7 @@ The :class:`UntypedActor` class defines only one abstract method, the above ment
|
|||
If the current actor behavior does not match a received message, it's recommended that
|
||||
you call the :meth:`unhandled` method, which by default publishes a ``new
|
||||
akka.actor.UnhandledMessage(message, sender, recipient)`` on the actor system’s
|
||||
event stream (set configuration item ``akka.actor.debug.unhandled`` to ``on``
|
||||
event stream (set configuration item ``akka.actor.debug.unhandled`` to ``on``
|
||||
to have them converted into actual Debug messages).
|
||||
|
||||
In addition, it offers:
|
||||
|
|
@ -230,7 +229,7 @@ mentioned above:
|
|||
in turn by its supervisor, or if an actor is restarted due to a sibling’s
|
||||
failure. If the message is available, then that message’s sender is also
|
||||
accessible in the usual way (i.e. by calling ``getSender()``).
|
||||
|
||||
|
||||
This method is the best place for cleaning up, preparing hand-over to the
|
||||
fresh actor instance, etc. By default it stops all children and calls
|
||||
:meth:`postStop`.
|
||||
|
|
@ -267,8 +266,10 @@ sent to a stopped actor will be redirected to the :obj:`deadLetters` of the
|
|||
:obj:`ActorSystem`.
|
||||
|
||||
|
||||
Identifying Actors
|
||||
==================
|
||||
.. _actorSelection-java:
|
||||
|
||||
Identifying Actors via Actor Selection
|
||||
======================================
|
||||
|
||||
As described in :ref:`addressing`, each actor has a unique logical path, which
|
||||
is obtained by following the chain of actors from child to parent until
|
||||
|
|
@ -277,11 +278,13 @@ differ if the supervision chain includes any remote supervisors. These paths
|
|||
are used by the system to look up actors, e.g. when a remote message is
|
||||
received and the recipient is searched, but they are also useful more directly:
|
||||
actors may look up other actors by specifying absolute or relative
|
||||
paths—logical or physical—and receive back an :class:`ActorRef` with the
|
||||
paths—logical or physical—and receive back an :class:`ActorSelection` with the
|
||||
result::
|
||||
|
||||
getContext().actorFor("/user/serviceA/actor") // will look up this absolute path
|
||||
getContext().actorFor("../joe") // will look up sibling beneath same supervisor
|
||||
// will look up this absolute path
|
||||
getContext().actorSelection("/user/serviceA/actor");
|
||||
// will look up sibling beneath same supervisor
|
||||
getContext().actorSelection("../joe");
|
||||
|
||||
The supplied path is parsed as a :class:`java.net.URI`, which basically means
|
||||
that it is split on ``/`` into path elements. If the path starts with ``/``, it
|
||||
|
|
@ -292,18 +295,43 @@ currently traversed actor, otherwise it will step “down” to the named child.
|
|||
It should be noted that the ``..`` in actor paths here always means the logical
|
||||
structure, i.e. the supervisor.
|
||||
|
||||
If the path being looked up does not exist, a special actor reference is
|
||||
returned which behaves like the actor system’s dead letter queue but retains
|
||||
its identity (i.e. the path which was looked up).
|
||||
The path elements of an actor selection may contain wildcard patterns allowing for
|
||||
broadcasting of messages to that section::
|
||||
|
||||
Remote actor addresses may also be looked up, if remoting is enabled::
|
||||
// will look all children to serviceB with names starting with worker
|
||||
getContext().actorSelection("/user/serviceB/worker*");
|
||||
// will look up all siblings beneath same supervisor
|
||||
getContext().actorSelection("../*");
|
||||
|
||||
getContext().actorFor("akka.tcp://app@otherhost:1234/user/serviceB")
|
||||
Messages can be sent via the :class:`ActorSelection` and the path of the
|
||||
:class:`ActorSelection` is looked up when delivering each message. If the selection
|
||||
does not match any actors the message will be dropped.
|
||||
|
||||
These look-ups return a (possibly remote) actor reference immediately, so you
|
||||
will have to send to it and await a reply in order to verify that ``serviceB``
|
||||
is actually reachable and running. An example demonstrating actor look-up is
|
||||
given in :ref:`remote-lookup-sample-java`.
|
||||
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
|
||||
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||
:class:`ActorRef`.
|
||||
|
||||
.. includecode:: code/docs/actor/UntypedActorDocTestBase.java
|
||||
:include: identify-imports,identify
|
||||
|
||||
Remote actor addresses may also be looked up, if :ref:`remoting <remoting-java>` is enabled::
|
||||
|
||||
getContext().actorSelection("akka.tcp://app@otherhost:1234/user/serviceB");
|
||||
|
||||
An example demonstrating remote actor look-up is given in :ref:`remote-lookup-sample-java`.
|
||||
|
||||
.. note::
|
||||
|
||||
``actorFor`` is deprecated in favor of ``actorSelection`` because actor references
|
||||
acquired with ``actorFor`` behave differently for local and remote actors.
|
||||
In the case of a local actor reference, the named actor needs to exist before the
|
||||
lookup, or else the acquired reference will be an :class:`EmptyLocalActorRef`.
|
||||
This will be true even if an actor with that exact path is created after acquiring
|
||||
the actor reference. For remote actor references acquired with `actorFor` the
|
||||
behaviour is different and sending messages to such a reference will under the hood
|
||||
look up the actor by path on the remote system for every message send.
|
||||
|
||||
Messages and immutability
|
||||
=========================
|
||||
|
|
@ -606,7 +634,7 @@ The other way of using :meth:`become` does not replace but add to the top of
|
|||
the behavior stack. In this case care must be taken to ensure that the number
|
||||
of “pop” operations (i.e. :meth:`unbecome`) matches the number of “push” ones
|
||||
in the long run, otherwise this amounts to a memory leak (which is why this
|
||||
behavior is not the default).
|
||||
behavior is not the default).
|
||||
|
||||
.. includecode:: code/docs/actor/UntypedActorSwapper.java#swapper
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,33 @@ available via the ``inbound`` boolean field of the event.
|
|||
|
||||
New configuration settings are also available, see the remoting documentation for more detail: :ref:`remoting-scala`
|
||||
|
||||
.. _migration_2.2_actorSelection:
|
||||
|
||||
Use ``actorSelection`` instead of ``actorFor``
|
||||
==============================================
|
||||
|
||||
``actorFor`` is deprecated in favor of ``actorSelection`` because actor references
|
||||
acquired with ``actorFor`` behave differently for local and remote actors.
|
||||
In the case of a local actor reference, the named actor needs to exist before the
|
||||
lookup, or else the acquired reference will be an :class:`EmptyLocalActorRef`.
|
||||
This will be true even if an actor with that exact path is created after acquiring
|
||||
the actor reference. For remote actor references acquired with `actorFor` the
|
||||
behaviour is different and sending messages to such a reference will under the hood
|
||||
look up the actor by path on the remote system for every message send.
|
||||
|
||||
Messages can be sent via the :class:`ActorSelection` and the path of the
|
||||
:class:`ActorSelection` is looked up when delivering each message. If the selection
|
||||
does not match any actors the message will be dropped.
|
||||
|
||||
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
|
||||
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||
:class:`ActorRef`.
|
||||
|
||||
Read more about ``actorSelection`` in :ref:`docs for Java <actorSelection-java>` or
|
||||
:ref:`docs for Scala <actorSelection-scala>`.
|
||||
|
||||
ActorRef equality and sending to remote actors
|
||||
==============================================
|
||||
|
||||
|
|
@ -159,15 +186,15 @@ Sending messages to an ``ActorRef`` must have the same semantics no matter if th
|
|||
on a remote host or in the same ``ActorSystem`` in the same JVM. This was not always the case. For example
|
||||
when the target actor is terminated and created again under the same path. Sending to local references
|
||||
of the previous incarnation of the actor will not be delivered to the new incarnation, but that was the case
|
||||
for remote references. The reason was that the target actor was looked up by its path on every message
|
||||
for remote references. The reason was that the target actor was looked up by its path on every message
|
||||
delivery and the path didn't distinguish between the two incarnations of the actor. This has been fixed, and
|
||||
sending messages to remote references that points to a terminated actor will not be delivered to a new
|
||||
sending messages to remote references that points to a terminated actor will not be delivered to a new
|
||||
actor with the same path.
|
||||
|
||||
Equality of ``ActorRef`` has been changed to match the intention that an ``ActorRef`` corresponds to the target
|
||||
actor instance. Two actor references are compared equal when they have the same path and point to the same
|
||||
actor incarnation. A reference pointing to a terminated actor does not compare equal to a reference pointing
|
||||
to another (re-created) actor with the same path. Note that a restart of an actor caused by a failure still
|
||||
to another (re-created) actor with the same path. Note that a restart of an actor caused by a failure still
|
||||
means that it's the same actor incarnation, i.e. a restart is not visible for the consumer of the ``ActorRef``.
|
||||
|
||||
Equality in 2.1 was only based on the path of the ``ActorRef``. If you need to keep track of actor references
|
||||
|
|
@ -175,8 +202,8 @@ in a collection and do not care about the exact actor incarnation you can use th
|
|||
the identifier of the target actor is not taken into account when comparing actor paths.
|
||||
|
||||
Remote actor references acquired with ``actorFor`` do not include the full information about the underlying actor
|
||||
identity and therefore such references do not compare equal to references acquired with ``actorOf``,
|
||||
``sender``, or ``context.self``. Because of this ``actorFor`` is deprecated, as explained in
|
||||
identity and therefore such references do not compare equal to references acquired with ``actorOf``,
|
||||
``sender``, or ``context.self``. Because of this ``actorFor`` is deprecated, as explained in
|
||||
:ref:`migration_2.2_actorSelection`.
|
||||
|
||||
Note that when a parent actor is restarted its children are by default stopped and re-created, i.e. the child
|
||||
|
|
@ -187,9 +214,32 @@ messages to remote deployed children of a restarted parent.
|
|||
This may also have implications if you compare the ``ActorRef`` received in a ``Terminated`` message
|
||||
with an expected ``ActorRef``.
|
||||
|
||||
.. _migration_2.2_actorSelection:
|
||||
The following will not match::
|
||||
|
||||
Use ``actorSelection`` instead of ``actorFor``
|
||||
==============================================
|
||||
val ref = context.actorFor("akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName")
|
||||
|
||||
FIXME: ticket #3074
|
||||
def receive = {
|
||||
case Terminated(`ref`) => // ...
|
||||
}
|
||||
|
||||
Instead, use actorSelection followed by identify request, and watch the verified actor reference::
|
||||
|
||||
val selection = context.actorSelection("akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName")
|
||||
selection ! Identify(None)
|
||||
var ref: ActorRef = _
|
||||
|
||||
def receive = {
|
||||
case ActorIdentity(_, Some(actorRef)) =>
|
||||
ref = actorRef
|
||||
context watch ref
|
||||
case ActorIdentity(_, None) => // not alive
|
||||
case Terminated(`ref`) => // ...
|
||||
}
|
||||
|
||||
|
||||
|
||||
Use ``watch`` instead of ``isTerminated``
|
||||
=========================================
|
||||
|
||||
``ActorRef.isTerminated`` is deprecated in favor of ``ActorContext.watch`` because
|
||||
``isTerminated`` behaves differently for local and remote actors.
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ Creating Actors
|
|||
Since Akka enforces parental supervision every actor is supervised and
|
||||
(potentially) the supervisor of its children, it is advisable that you
|
||||
familiarize yourself with :ref:`actor-systems` and :ref:`supervision` and it
|
||||
may also help to read :ref:`actorOf-vs-actorFor` (the whole of
|
||||
:ref:`addressing` is recommended reading in any case).
|
||||
may also help to read :ref:`addressing`.
|
||||
|
||||
Defining an Actor class
|
||||
-----------------------
|
||||
|
|
@ -220,7 +219,7 @@ detects if the runtime class of the statically given actor subtype extends the
|
|||
:class:`Stash` trait (this is a complicated way of saying that ``new Act with
|
||||
Stash`` would not work because its runtime erased type is just an anonymous
|
||||
subtype of ``Act``). The purpose is to automatically use a dispatcher with the
|
||||
appropriate deque-based mailbox, ``akka.actor.default-stash-dispatcher``.
|
||||
appropriate deque-based mailbox, ``akka.actor.default-stash-dispatcher``.
|
||||
If you want to use this magic, simply extend :class:`ActWithStash`:
|
||||
|
||||
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#act-with-stash
|
||||
|
|
@ -343,7 +342,7 @@ mentioned above:
|
|||
in turn by its supervisor, or if an actor is restarted due to a sibling’s
|
||||
failure. If the message is available, then that message’s sender is also
|
||||
accessible in the usual way (i.e. by calling ``sender``).
|
||||
|
||||
|
||||
This method is the best place for cleaning up, preparing hand-over to the
|
||||
fresh actor instance, etc. By default it stops all children and calls
|
||||
:meth:`postStop`.
|
||||
|
|
@ -378,8 +377,10 @@ to run after message queuing has been disabled for this actor, i.e. messages
|
|||
sent to a stopped actor will be redirected to the :obj:`deadLetters` of the
|
||||
:obj:`ActorSystem`.
|
||||
|
||||
Identifying Actors
|
||||
==================
|
||||
.. _actorSelection-scala:
|
||||
|
||||
Identifying Actors via Actor Selection
|
||||
======================================
|
||||
|
||||
As described in :ref:`addressing`, each actor has a unique logical path, which
|
||||
is obtained by following the chain of actors from child to parent until
|
||||
|
|
@ -388,11 +389,13 @@ differ if the supervision chain includes any remote supervisors. These paths
|
|||
are used by the system to look up actors, e.g. when a remote message is
|
||||
received and the recipient is searched, but they are also useful more directly:
|
||||
actors may look up other actors by specifying absolute or relative
|
||||
paths—logical or physical—and receive back an :class:`ActorRef` with the
|
||||
paths—logical or physical—and receive back an :class:`ActorSelection` with the
|
||||
result::
|
||||
|
||||
context.actorFor("/user/serviceA/aggregator") // will look up this absolute path
|
||||
context.actorFor("../joe") // will look up sibling beneath same supervisor
|
||||
// will look up this absolute path
|
||||
context.actorSelection("/user/serviceA/aggregator")
|
||||
// will look up sibling beneath same supervisor
|
||||
context.actorSelection("../joe")
|
||||
|
||||
The supplied path is parsed as a :class:`java.net.URI`, which basically means
|
||||
that it is split on ``/`` into path elements. If the path starts with ``/``, it
|
||||
|
|
@ -403,18 +406,42 @@ currently traversed actor, otherwise it will step “down” to the named child.
|
|||
It should be noted that the ``..`` in actor paths here always means the logical
|
||||
structure, i.e. the supervisor.
|
||||
|
||||
If the path being looked up does not exist, a special actor reference is
|
||||
returned which behaves like the actor system’s dead letter queue but retains
|
||||
its identity (i.e. the path which was looked up).
|
||||
The path elements of an actor selection may contain wildcard patterns allowing for
|
||||
broadcasting of messages to that section::
|
||||
|
||||
Remote actor addresses may also be looked up, if remoting is enabled::
|
||||
// will look all children to serviceB with names starting with worker
|
||||
context.actorSelection("/user/serviceB/worker*")
|
||||
// will look up all siblings beneath same supervisor
|
||||
context.actorSelection("../*")
|
||||
|
||||
context.actorFor("akka.tcp://app@otherhost:1234/user/serviceB")
|
||||
Messages can be sent via the :class:`ActorSelection` and the path of the
|
||||
:class:`ActorSelection` is looked up when delivering each message. If the selection
|
||||
does not match any actors the message will be dropped.
|
||||
|
||||
These look-ups return a (possibly remote) actor reference immediately, so you
|
||||
will have to send to it and await a reply in order to verify that ``serviceB``
|
||||
is actually reachable and running. An example demonstrating actor look-up is
|
||||
given in :ref:`remote-lookup-sample-scala`.
|
||||
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
|
||||
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||
:class:`ActorRef`.
|
||||
|
||||
.. includecode:: code/docs/actor/ActorDocSpec.scala#identify
|
||||
|
||||
Remote actor addresses may also be looked up, if :ref:`remoting <remoting-scala>` is enabled::
|
||||
|
||||
context.actorSelection("akka.tcp://app@otherhost:1234/user/serviceB")
|
||||
|
||||
An example demonstrating actor look-up is given in :ref:`remote-lookup-sample-scala`.
|
||||
|
||||
.. note::
|
||||
|
||||
``actorFor`` is deprecated in favor of ``actorSelection`` because actor references
|
||||
acquired with ``actorFor`` behaves different for local and remote actors.
|
||||
In the case of a local actor reference, the named actor needs to exist before the
|
||||
lookup, or else the acquired reference will be an :class:`EmptyLocalActorRef`.
|
||||
This will be true even if an actor with that exact path is created after acquiring
|
||||
the actor reference. For remote actor references acquired with `actorFor` the
|
||||
behaviour is different and sending messages to such a reference will under the hood
|
||||
look up the actor by path on the remote system for every message send.
|
||||
|
||||
Messages and immutability
|
||||
=========================
|
||||
|
|
@ -721,7 +748,7 @@ The other way of using :meth:`become` does not replace but add to the top of
|
|||
the behavior stack. In this case care must be taken to ensure that the number
|
||||
of “pop” operations (i.e. :meth:`unbecome`) matches the number of “push” ones
|
||||
in the long run, otherwise this amounts to a memory leak (which is why this
|
||||
behavior is not the default).
|
||||
behavior is not the default).
|
||||
|
||||
.. includecode:: code/docs/actor/ActorDocSpec.scala#swapper
|
||||
|
||||
|
|
|
|||
|
|
@ -327,6 +327,37 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
|
|||
expectMsg("finished")
|
||||
}
|
||||
|
||||
"using Identify" in {
|
||||
//#identify
|
||||
import akka.actor.{ Actor, Props, Identify, ActorIdentity, Terminated }
|
||||
|
||||
class Follower extends Actor {
|
||||
val identifyId = 1
|
||||
context.actorSelection("/user/another") ! Identify(identifyId)
|
||||
|
||||
def receive = {
|
||||
case ActorIdentity(`identifyId`, Some(ref)) ⇒
|
||||
context.watch(ref)
|
||||
context.become(active(ref))
|
||||
case ActorIdentity(`identifyId`, None) ⇒ context.stop(self)
|
||||
|
||||
}
|
||||
|
||||
def active(another: ActorRef): Actor.Receive = {
|
||||
case Terminated(`another`) ⇒ context.stop(self)
|
||||
}
|
||||
}
|
||||
//#identify
|
||||
|
||||
val a = system.actorOf(Props(new Actor {
|
||||
def receive = Actor.emptyBehavior
|
||||
}))
|
||||
val b = system.actorOf(Props(new Follower))
|
||||
watch(b)
|
||||
system.stop(a)
|
||||
expectMsgType[akka.actor.Terminated].actor must be === b
|
||||
}
|
||||
|
||||
"using pattern gracefulStop" in {
|
||||
val actorRef = system.actorOf(Props[MyActor])
|
||||
//#gracefulStop
|
||||
|
|
@ -386,9 +417,9 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
|
|||
lastSender must be === actor
|
||||
actor ! me
|
||||
expectMsg("reply")
|
||||
lastSender must be === system.actorFor("/user")
|
||||
lastSender.path.elements.mkString("/", "/", "") must be === "/user"
|
||||
expectMsg("reply")
|
||||
lastSender must be === system.actorFor("/user")
|
||||
lastSender.path.elements.mkString("/", "/", "") must be === "/user"
|
||||
}
|
||||
|
||||
"using ActorDSL outside of akka.actor package" in {
|
||||
|
|
|
|||
|
|
@ -4,17 +4,15 @@
|
|||
package docs.actor
|
||||
|
||||
import language.postfixOps
|
||||
|
||||
//#imports
|
||||
import scala.concurrent.{ Promise, Future, Await }
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.{ ActorContext, TypedActor, TypedProps }
|
||||
|
||||
//#imports
|
||||
|
||||
import org.scalatest.{ BeforeAndAfterAll, WordSpec }
|
||||
import org.scalatest.matchers.MustMatchers
|
||||
import akka.testkit._
|
||||
//#typed-actor-impl
|
||||
import java.lang.String.{ valueOf ⇒ println } //Mr funny man avoids printing to stdout AND keeping docs alright
|
||||
import akka.actor.ActorRef
|
||||
|
||||
//#typed-actor-iface
|
||||
trait Squarer {
|
||||
|
|
@ -46,8 +44,6 @@ class SquarerImpl(val name: String) extends Squarer {
|
|||
def squareNow(i: Int): Int = i * i
|
||||
//#typed-actor-impl-methods
|
||||
}
|
||||
//#typed-actor-impl
|
||||
import java.lang.String.{ valueOf ⇒ println } //Mr funny man avoids printing to stdout AND keeping docs alright
|
||||
//#typed-actor-supercharge
|
||||
trait Foo {
|
||||
def doFoo(times: Int): Unit = println("doFoo(" + times + ")")
|
||||
|
|
@ -145,12 +141,13 @@ class TypedActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
|
|||
}
|
||||
|
||||
"proxy any ActorRef" in {
|
||||
val actorRefToRemoteActor: ActorRef = system.deadLetters
|
||||
//#typed-actor-remote
|
||||
val typedActor: Foo with Bar =
|
||||
TypedActor(system).
|
||||
typedActorOf(
|
||||
TypedProps[FooBar],
|
||||
system.actorFor("akka://SomeSystem@somehost:2552/user/some/foobar"))
|
||||
actorRefToRemoteActor)
|
||||
//Use "typedActor" as a FooBar
|
||||
//#typed-actor-remote
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ import akka.routing.RoundRobinRouter
|
|||
import akka.testkit._
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.ActorPath
|
||||
|
||||
object RouterViaProgramDocSpec {
|
||||
case class Message1(nbr: Int)
|
||||
case class Reply1(name: String, m: Message1)
|
||||
|
||||
class ExampleActor1 extends Actor {
|
||||
def receive = {
|
||||
case m @ Message1(nbr) ⇒ sender ! ((self, m))
|
||||
case m @ Message1(nbr) ⇒ sender ! Reply1(self.path.name, m)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -43,9 +45,9 @@ class RouterViaProgramDocSpec extends AkkaSpec with ImplicitSender {
|
|||
1 to 6 foreach { i ⇒ router ! Message1(i) }
|
||||
val received = receiveN(6, 5.seconds.dilated)
|
||||
1 to 6 foreach { i ⇒
|
||||
val expectedActor = system.actorFor(routees((i - 1) % routees.length))
|
||||
val expectedName = (routees((i - 1) % routees.length)).split("/").last
|
||||
val expectedMsg = Message1(i)
|
||||
received must contain[AnyRef]((expectedActor, expectedMsg))
|
||||
received must contain[AnyRef](Reply1(expectedName, expectedMsg))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ package docs.serialization {
|
|||
|
||||
"demonstrate serialization of ActorRefs" in {
|
||||
val theActorRef: ActorRef = system.deadLetters
|
||||
val theActorSystem: ActorSystem = system
|
||||
val extendedSystem: ExtendedActorSystem = system.asInstanceOf[ExtendedActorSystem]
|
||||
|
||||
//#actorref-serializer
|
||||
// Serialize
|
||||
|
|
@ -168,7 +168,7 @@ package docs.serialization {
|
|||
|
||||
// Deserialize
|
||||
// (beneath fromBinary)
|
||||
val deserializedActorRef = theActorSystem actorFor identifier
|
||||
val deserializedActorRef = extendedSystem.provider.resolveActorRef(identifier)
|
||||
// Then just use the ActorRef
|
||||
//#actorref-serializer
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ package docs.serialization {
|
|||
}
|
||||
|
||||
def serializeTo(ref: ActorRef, remote: Address): String =
|
||||
ref.path.toSerializationFormatWithAddress(ExternalAddress(theActorSystem).addressFor(remote))
|
||||
ref.path.toSerializationFormatWithAddress(ExternalAddress(extendedSystem).addressFor(remote))
|
||||
//#external-address
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -208,10 +208,13 @@ class TestkitDocSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
|
|||
|
||||
"demonstrate probe watch" in {
|
||||
import akka.testkit.TestProbe
|
||||
val target = system.actorFor("/buh")
|
||||
val target = system.actorOf(Props(new Actor {
|
||||
def receive = Actor.emptyBehavior
|
||||
}))
|
||||
//#test-probe-watch
|
||||
val probe = TestProbe()
|
||||
probe watch target
|
||||
target ! PoisonPill
|
||||
probe.expectMsgType[Terminated].actor must be(target)
|
||||
//#test-probe-watch
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ Types of Remote Interaction
|
|||
|
||||
Akka has two ways of using remoting:
|
||||
|
||||
* Lookup : used to look up an actor on a remote node with ``actorFor(path)``
|
||||
* Lookup : used to look up an actor on a remote node with ``actorSelection(path)``
|
||||
* Creation : used to create an actor on a remote node with ``actorOf(Props(...), actorName)``
|
||||
|
||||
In the next sections the two alternatives are described in detail.
|
||||
|
|
@ -77,17 +77,24 @@ In the next sections the two alternatives are described in detail.
|
|||
Looking up Remote Actors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``actorFor(path)`` will obtain an ``ActorRef`` to an Actor on a remote node, e.g.::
|
||||
``actorSelection(path)`` will obtain an ``ActorSelection`` to an Actor on a remote node, e.g.::
|
||||
|
||||
val actor = context.actorFor("akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName")
|
||||
val selection =
|
||||
context.actorSelection("akka.tcp://actorSystemName@10.0.0.1:2552/user/actorName")
|
||||
|
||||
As you can see from the example above the following pattern is used to find an ``ActorRef`` on a remote node::
|
||||
As you can see from the example above the following pattern is used to find an actor on a remote node::
|
||||
|
||||
akka.<protocol>://<actor system>@<hostname>:<port>/<actor path>
|
||||
|
||||
Once you obtained a reference to the actor you can interact with it they same way you would with a local actor, e.g.::
|
||||
Once you obtained a selection to the actor you can interact with it they same way you would with a local actor, e.g.::
|
||||
|
||||
actor ! "Pretty awesome feature"
|
||||
selection ! "Pretty awesome feature"
|
||||
|
||||
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
|
||||
the actor. There is a built-in ``Identify`` message that all Actors will understand
|
||||
and automatically reply to with a ``ActorIdentity`` message containing the
|
||||
:class:`ActorRef`.
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -271,9 +278,9 @@ and it is created from an actor system using the aforementioned client’s confi
|
|||
.. includecode:: ../../../akka-samples/akka-sample-remote/src/main/scala/sample/remote/calculator/LookupApplication.scala
|
||||
:include: setup
|
||||
|
||||
Requests which come in via ``doSomething`` will be sent to the client actor
|
||||
along with the reference which was looked up earlier. Observe how the actor
|
||||
system name using in ``actorFor`` matches the remote system’s name, as do IP
|
||||
Requests which come in via ``doSomething`` will be sent to the client actor,
|
||||
which will use the actor reference that was identified earlier. Observe how the actor
|
||||
system name using in ``actorSelection`` matches the remote system’s name, as do IP
|
||||
and port number. Top-level actors are always created below the ``"/user"``
|
||||
guardian, which supervises them.
|
||||
|
||||
|
|
@ -481,15 +488,15 @@ SSL
|
|||
SSL can be used as the remote transport by adding ``akka.remote.netty.ssl``
|
||||
to the ``enabled-transport`` configuration section. See a description of the settings
|
||||
in the :ref:`remoting-scala-configuration` section.
|
||||
|
||||
The SSL support is implemented with Java Secure Socket Extension, please consult the offical
|
||||
|
||||
The SSL support is implemented with Java Secure Socket Extension, please consult the offical
|
||||
`Java Secure Socket Extension documentation <http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html>`_
|
||||
and related resources for troubleshooting.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
When using SHA1PRNG on Linux it's recommended specify ``-Djava.security.egd=file:/dev/./urandom`` as argument
|
||||
When using SHA1PRNG on Linux it's recommended specify ``-Djava.security.egd=file:/dev/./urandom`` as argument
|
||||
to the JVM to prevent blocking. It is NOT as secure because it reuses the seed.
|
||||
Use '/dev/./urandom', not '/dev/urandom' as that doesn't work according to
|
||||
Use '/dev/./urandom', not '/dev/urandom' as that doesn't work according to
|
||||
`Bug ID: 6202721 <http://bugs.sun.com/view_bug.do?bug_id=6202721>`_.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ Proxying
|
|||
--------
|
||||
|
||||
You can use the ``typedActorOf`` that takes a TypedProps and an ActorRef to proxy the given ActorRef as a TypedActor.
|
||||
This is usable if you want to communicate remotely with TypedActors on other machines, just look them up with ``actorFor`` and pass the ``ActorRef`` to ``typedActorOf``.
|
||||
This is usable if you want to communicate remotely with TypedActors on other machines, just pass the ``ActorRef`` to ``typedActorOf``.
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ This is usable if you want to communicate remotely with TypedActors on other mac
|
|||
Lookup & Remoting
|
||||
-----------------
|
||||
|
||||
Since ``TypedActors`` are backed by ``Akka Actors``, you can use ``actorFor`` together with ``typedActorOf`` to proxy ``ActorRefs`` potentially residing on remote nodes.
|
||||
Since ``TypedActors`` are backed by ``Akka Actors``, you can use ``typedActorOf`` to proxy ``ActorRefs`` potentially residing on remote nodes.
|
||||
|
||||
.. includecode:: code/docs/actor/TypedActorDocSpec.scala#typed-actor-remote
|
||||
|
||||
|
|
|
|||
|
|
@ -516,10 +516,10 @@ in case classes with proper type information. But one particular useful feature
|
|||
of Akka actors is that they have a stable identity by which they can be found,
|
||||
a unique name. This name is represented as a :class:`String` and naturally does
|
||||
not bear any type information concerning the actor’s channels. Thus, when
|
||||
looking up an actor with ``system.actorFor(...)`` you will only get an untyped
|
||||
:class:`ActorRef` and not a channel reference. This :class:`ActorRef` can of
|
||||
course manually be wrapped in a channel reference bearing the desired channels,
|
||||
but this is not a type-safe operation.
|
||||
looking up an actor with ``system.actorSelection(...)`` followed by an ``Identify``
|
||||
request you will only get an untyped :class:`ActorRef` and not a channel reference.
|
||||
This :class:`ActorRef` can of course manually be wrapped in a channel reference
|
||||
bearing the desired channels, but this is not a type-safe operation.
|
||||
|
||||
The solution in this case must be a runtime check. There is an operation to
|
||||
“narrow” an :class:`ActorRef` to a channel reference of given type, which
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue