Java Pattern - Exception propagation in actor hierarchy using supervision
Ticket #2605
This commit is contained in:
parent
89c1f66b1f
commit
1b34290d4c
2 changed files with 129 additions and 1 deletions
45
akka-docs/rst/java/code/docs/pattern/JavaAsk.java
Normal file
45
akka-docs/rst/java/code/docs/pattern/JavaAsk.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
.. _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
|
||||
: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
|
||||
================
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue