Java Pattern - Exception propagation in actor hierarchy using supervision

Ticket #2605
This commit is contained in:
RickLatrine 2012-10-06 17:18:30 +02:00
parent 89c1f66b1f
commit 1b34290d4c
2 changed files with 129 additions and 1 deletions

View file

@ -0,0 +1,45 @@
public class JavaAsk extends UntypedActor {
private ActorRef targetActor;
private ActorRef caller;
private static class AskParam {
Props props;
Object message;
AskParam(Props props, Object message) {
this.props = props;
this.message = message;
}
}
@Override
public SupervisorStrategy supervisorStrategy() {
return new OneForOneStrategy(0, Duration.Zero(), new Function<Throwable, Directive>() {
public Directive apply(Throwable cause) {
caller.tell(new Status.Failure(cause));
return SupervisorStrategy.stop();
}
});
}
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof AskParam) {
AskParam param = (AskParam) message;
caller = getSender();
targetActor = getContext().actorOf(param.props);
targetActor.forward(param.message, getContext());
} else
unhandled(message);
}
public static void ask(ActorSystem system, Props props, Object message, Timeout timeout) throws Exception {
ActorRef javaAsk = system.actorOf(Props.apply(JavaAsk.class));
try {
AskParam param = new AskParam(props, message);
Future<Object> finished = Patterns.ask(javaAsk, param, timeout);
Await.result(finished, timeout.duration());
} finally {
system.stop(javaAsk);
}
}
}

View file

@ -1,4 +1,3 @@
.. _howto-java: .. _howto-java:
###################### ######################
@ -17,6 +16,90 @@ sense to add to the ``akka.pattern`` package for creating an `OTP-like library
You might find some of the patterns described in the Scala chapter of You might find some of the patterns described in the Scala chapter of
:ref:`howto-scala` useful even though the example code is written in Scala. :ref:`howto-scala` useful even though the example code is written in Scala.
Exception propagation in actor hierarchy using supervision
==========================================================
*Contributed by: Rick Latrine*
A nice way to enter the actor world from java is the use of Patterns.ask().
This method starts a temporary actor to forward the message and collect the result from the actor to be "asked".
In case of errors within the asked actor the default supervision handling will take over.
The caller of Patterns.ask() will not be notified.
If that caller is interested in such an exception, he must reply to the temporary actor with Status.Failure(Throwable).
Behind the asked actor a complex actor hierarchy might be spawned to accomplish asynchronous work.
Then supervision is the established way to control error handling.
Unfortunately the asked actor must know about supervision and must catch the exceptions.
Such an actor is unlikely to be reused in a different actor hierarchy and contains crippled try/catch blocks.
This pattern provides a way to encapsulate supervision and error propagation to the temporary actor.
Finally the exception occurred in the asked actor is thrown by Patterns.ask().
Let's have a look at the example code:
.. code-block:: java
public class JavaAsk extends UntypedActor {
private ActorRef targetActor;
private ActorRef caller;
private static class AskParam {
Props props;
Object message;
AskParam(Props props, Object message) {
this.props = props;
this.message = message;
}
}
@Override
public SupervisorStrategy supervisorStrategy() {
return new OneForOneStrategy(0, Duration.Zero(), new Function<Throwable, Directive>() {
public Directive apply(Throwable cause) {
caller.tell(new Status.Failure(cause));
return SupervisorStrategy.stop();
}
});
}
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof AskParam) {
AskParam param = (AskParam) message;
caller = getSender();
targetActor = getContext().actorOf(param.props);
targetActor.forward(param.message, getContext());
} else
unhandled(message);
}
public static void ask(ActorSystem system, Props props, Object message, Timeout timeout) throws Exception {
ActorRef javaAsk = system.actorOf(Props.apply(JavaAsk.class));
try {
AskParam param = new AskParam(props, message);
Future<Object> finished = Patterns.ask(javaAsk, param, timeout);
Await.result(finished, timeout.duration());
} finally {
system.stop(javaAsk);
}
}
}
}
In the ask method the parent actor is started.
The parent is sent which child it should create and which message is to be forwarded.
On receiving these parameteres the parent actor creates the target/child actor.
The message is forwarded in order to let the child actor reply the result directly to the temporary actor.
In case of an exception the supervisor tells the temporary actor which exception was thrown.
Afterwards the actor hierarchy is stopped.
The exception will be thrown by the ask method.
Finally we are able to execute an actor and receive the results or exceptions synchronously.
Template Pattern Template Pattern
================ ================