public abstract class TryCatchFinally extends Object implements Cancelable
SWF Flow error handling relies on the idea that any asynchronous task (which
includes methods annotated as Asynchronous
) is executed in a parent
context. In the case of an exception being thrown from a task, all sibling
tasks that share the same parent context are canceled. After successful
cancellation the exception is propagated to the parent context for handling.
TryCatchFinally
doTry()
, doFinally()
and
doCatch(Throwable)
methods serve as parent scopes for tasks created
during their execution.
For example if any Task
(or method annotated with
Asynchronous
) that originates (possibly indirectly through parent
task) in doTry()
throws an exception all other tasks that originated
in doTry()
are canceled and only then doCatch(Throwable)
is
called. Through this cancellation mechanism it is guaranteed that
doCatch(Throwable)
is called at most once even if there are multiple
parallel tasks executing in the doTry()
scope.
If failure happens in a task originated in doCatch(Throwable)
then
all its siblings are canceled first and then doFinally()
is called.
The same happens if task originated in doFinally()
fails. All it
siblings are canceled and then parent scope of the
TryCatchFinally
is given chance to handle the exception.
The cancellation semantic depends on the task implementation. Task
(or method annotated with Asynchronous
) that has not started
execution is never given chance to execute after cancellation. Task which is
already executing is not interrupted and completes (or fails).
ExternalTask
cancellation depends on the external resource. For
example SWF activities and child workflows that are modeled as
ExternalTask
s are canceled through SWF API.
When TryCatchFinally
itself is canceled because of sibling task
failure it handles its own cancellation in the following order:
TryCatchFinally
is
considered canceled immediately.doTry()
then
cancellation of all of them is requested.doCatch(Throwable)
with CancellationException
.doFinally()
.doFinally()
are completed consider
TryCathFinally canceled
doCatch(Throwable)
and doFinally()
are not cancelable. It means that cancellation request always waits
for completion of all tasks that originate in these methods. Special care
should be taken when writing code in doCatch(Throwable)
and in
doFinally()
to ensure that in all possible failure scenarios they
don't end up in a stuck state.
TryCatchFinally
can be canceled explicitly through
cancel(Throwable)
method. In case of explicit cancellation any
exception including CancellationException
that is rethrown from
doCatch(Throwable)
or doFinally()
is propagated to the
parent context.
It is pretty common to have tasks that have their lifecycle linked to some
other tasks. For example notification activity that is sent out if some other
activity is not completed in a specified period of time. The timer and the
notification activity should be canceled as soon as the monitored activity is
completed. Such use case can be supported by wrapping timer and notification
activity in TryCatchFinally
which is explicitly canceled upon
monitored activity completion. The more convenient way to perform such
cleanup is by marking a Task (or method annotated with Asynchronous
)
as daemon. The asynchronous scope in absence of failures is executed in the
following sequence:
doTry()
) is executed.
Pass true
to the first argument of
Task.Task(boolean, Promise...)
constructor to mark a Task as daemon.
Use Asynchronous.daemon()
annotation parameter to mark an
asynchronous method as daemon. Any task that is created during execution of a
daemon task is marked as daemon. TryCatchFinally
also can be
marked as daemon through TryCatchFinally(boolean, Promise...)
constructor or by by being created by a daemon task. Note that
TryCatchFinally doesn't pass its daemon flag to tasks created in
doTry()
, doCatch(Throwable)
and doFinally()
. It is
because each of these methods acts as a separate asynchronous scope and the
rules of execution described above apply to them.
In case of multiple simultaneous exceptions (which is possible for external
tasks) or if cancellation of a child results in any exception that is not
CancellationException
the last exception "wins". I.e. it becomes the
exception delivered to doCatch(Throwable)
method.
Note that instances of Promise
do not participate in error handling
the way Future
does. If method that returns Promise throws an
exception the Promise state and return value are not changed. It is similar
to behavior of variables in case of synchronous code.
Basic error handling:
new TryCatchFinally() { final List<Promise<String>> instances = new ArrayList<Promise<String>>(); protected void doTry() throws Throwable { for (int i = 0; i < count; i++) { Promise<String> instanceId = ec2.startInstance(); instances.add(instanceId); } performSimulation(instances); } protected void doCatch(Throwable e) throws Throwable { mail.notifySimulationFailure(e); } protected void doFinally() throws Throwable { for (int i = 0; i < count; i++) { Promise<String> instanceId = instances.get(i); if (instanceId.isReady()) { ec2.stopInstance(instanceId.get()); } } } };
Daemon example:
protected void doTry() throws Throwable { for (int i = 0; i < count; i++) { Promise<String> instanceId = ec2.startInstance(); instances.add(instanceId); } performSimulation(instances); notifyOnDelay(); } @Asynchronous(daemon = true) public void notifyOnDelay() { Promise<Void> timer = clock.scheduleTimer(3600); mail.notifyDelay(timer); }
Modifier and Type | Class and Description |
---|---|
static class |
TryCatchFinally.State |
Constructor and Description |
---|
TryCatchFinally() |
TryCatchFinally(com.amazonaws.services.simpleworkflow.flow.core.AsyncContextAware parent,
boolean daemon,
Promise<?>... waitFor) |
TryCatchFinally(com.amazonaws.services.simpleworkflow.flow.core.AsyncContextAware parent,
Promise<?>... waitFor) |
TryCatchFinally(boolean daemon,
Promise<?>... waitFor) |
TryCatchFinally(Promise<?>... waitFor) |
Modifier and Type | Method and Description |
---|---|
void |
cancel(Throwable cause) |
List<AsyncTaskInfo> |
getAsynchronousStackTraceDump() |
String |
getAsynchronousStackTraceDumpAsString() |
String |
getName() |
StackTraceElement[] |
getStackTrace() |
TryCatchFinally.State |
getState() |
boolean |
isCancelRequested() |
void |
setName(String name) |
String |
toString() |
public TryCatchFinally()
public TryCatchFinally(Promise<?>... waitFor)
public TryCatchFinally(boolean daemon, Promise<?>... waitFor)
public TryCatchFinally(com.amazonaws.services.simpleworkflow.flow.core.AsyncContextAware parent, boolean daemon, Promise<?>... waitFor)
public TryCatchFinally(com.amazonaws.services.simpleworkflow.flow.core.AsyncContextAware parent, Promise<?>... waitFor)
public String getName()
public void setName(String name)
public void cancel(Throwable cause)
cancel
in interface Cancelable
public boolean isCancelRequested()
isCancelRequested
in interface Cancelable
public StackTraceElement[] getStackTrace()
public List<AsyncTaskInfo> getAsynchronousStackTraceDump()
public String getAsynchronousStackTraceDumpAsString()
public TryCatchFinally.State getState()
Copyright © 2013 Amazon Web Services, Inc. All Rights Reserved.