Skip to content

Commit 49e77f6

Browse files
authored
HelloException added (#4)
1 parent 503b457 commit 49e77f6

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
7+
* use this file except in compliance with the License. A copy of the License is
8+
* located at
9+
*
10+
* http://aws.amazon.com/apache2.0
11+
*
12+
* or in the "license" file accompanying this file. This file is distributed on
13+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14+
* express or implied. See the License for the specific language governing
15+
* permissions and limitations under the License.
16+
*/
17+
package com.uber.cadence.samples.hello;
18+
19+
import com.google.common.base.Throwables;
20+
import com.uber.cadence.client.WorkflowClient;
21+
import com.uber.cadence.client.WorkflowException;
22+
import com.uber.cadence.client.WorkflowOptions;
23+
import com.uber.cadence.worker.Worker;
24+
import com.uber.cadence.workflow.ActivityOptions;
25+
import com.uber.cadence.workflow.Workflow;
26+
import com.uber.cadence.workflow.WorkflowMethod;
27+
import org.apache.log4j.BasicConfigurator;
28+
import org.apache.log4j.Level;
29+
import org.apache.log4j.Logger;
30+
31+
import java.io.IOException;
32+
33+
import static com.uber.cadence.samples.common.SampleConstants.DOMAIN;
34+
35+
/**
36+
* Demonstrates exception propagation across activity, child workflow and workflow client boundaries.
37+
* Shows how to deal with checked exceptions.
38+
* <li>
39+
* <ul>
40+
* Exceptions thrown by an activity are received by the workflow wrapped into an {@link com.uber.cadence.workflow.ActivityFailureException}.
41+
* </ul>
42+
* <ul>
43+
* Exceptions thrown by a child workflow are received by a parent workflow wrapped into a {@link com.uber.cadence.workflow.ChildWorkflowFailureException}.
44+
* </ul>
45+
* <ul>
46+
* Exceptions thrown by a workflow are received by a workflow client wrapped into {@link com.uber.cadence.client.WorkflowFailureException}.
47+
* </ul>
48+
* </li>
49+
* <p>
50+
* In this example a Workflow Client executes a workflow which executes a child workflow
51+
* which executes activity which throws an IOException. The resulting exception stack trace is:
52+
* <pre>
53+
* com.uber.cadence.client.WorkflowFailureException: WorkflowType="GreetingWorkflow::getGreeting", WorkflowID="38b9ce7a-e370-4cd8-a9f3-35e7295f7b3d", RunID="37ceb58c-9271-4fca-b5aa-ba06c5495214
54+
* at com.uber.cadence.internal.dispatcher.UntypedWorkflowStubImpl.getResult(UntypedWorkflowStubImpl.java:139)
55+
* at com.uber.cadence.internal.dispatcher.UntypedWorkflowStubImpl.getResult(UntypedWorkflowStubImpl.java:111)
56+
* at com.uber.cadence.internal.dispatcher.WorkflowExternalInvocationHandler.startWorkflow(WorkflowExternalInvocationHandler.java:187)
57+
* at com.uber.cadence.internal.dispatcher.WorkflowExternalInvocationHandler.invoke(WorkflowExternalInvocationHandler.java:113)
58+
* at com.sun.proxy.$Proxy2.getGreeting(Unknown Source)
59+
* at com.uber.cadence.samples.hello.HelloException.main(HelloException.java:117)
60+
* Caused by: com.uber.cadence.workflow.ChildWorkflowFailureException: WorkflowType="GreetingChild::composeGreeting", ID="37ceb58c-9271-4fca-b5aa-ba06c5495214:1", RunID="47859b47-da4c-4225-876a-462421c98c72, EventID=10
61+
* at java.lang.Thread.getStackTrace(Thread.java:1559)
62+
* at com.uber.cadence.internal.dispatcher.ChildWorkflowInvocationHandler.executeChildWorkflow(ChildWorkflowInvocationHandler.java:114)
63+
* at com.uber.cadence.internal.dispatcher.ChildWorkflowInvocationHandler.invoke(ChildWorkflowInvocationHandler.java:71)
64+
* at com.sun.proxy.$Proxy5.composeGreeting(Unknown Source:0)
65+
* at com.uber.cadence.samples.hello.HelloException$GreetingWorkflowImpl.getGreeting(HelloException.java:70)
66+
* at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method:0)
67+
* at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
68+
* at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
69+
* at java.lang.reflect.Method.invoke(Method.java:498)
70+
* at com.uber.cadence.internal.worker.POJOWorkflowImplementationFactory$POJOWorkflowImplementation.execute(POJOWorkflowImplementationFactory.java:160)
71+
* Caused by: com.uber.cadence.workflow.ActivityFailureException: ActivityType="GreetingActivities::composeGreeting" ActivityID="1", EventID=7
72+
* at java.lang.Thread.getStackTrace(Thread.java:1559)
73+
* at com.uber.cadence.internal.dispatcher.ActivityInvocationHandler.invoke(ActivityInvocationHandler.java:75)
74+
* at com.sun.proxy.$Proxy6.composeGreeting(Unknown Source:0)
75+
* at com.uber.cadence.samples.hello.HelloException$GreetingChildImpl.composeGreeting(HelloException.java:85)
76+
* ... 5 more
77+
* Caused by: java.io.IOException: Hello World!
78+
* at com.uber.cadence.samples.hello.HelloException$GreetingActivitiesImpl.composeGreeting(HelloException.java:93)
79+
* at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method:0)
80+
* at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
81+
* at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
82+
* at java.lang.reflect.Method.invoke(Method.java:498)
83+
* at com.uber.cadence.internal.worker.POJOActivityImplementationFactory$POJOActivityImplementation.execute(POJOActivityImplementationFactory.java:162)
84+
*
85+
* </pre>
86+
* Note that there is only one level of wrapping when crossing logical process boundaries. And that wrapper exception
87+
* adds a lot of relevant information about failure.
88+
* <p>
89+
* {@link IOException} is a checked exception. The standard Java way of adding <code>throws IOException</code> to
90+
* activity, child and workflow interfaces is not going to help. It is because at all levels it is never received directly, but
91+
* in wrapped form. Propagating it without wrapping would not allow adding additional context information
92+
* like activity, child workflow and parent workflow types and IDs. The Cadence library solution is to provide special
93+
* wrapper method {@link Workflow#throwWrapped(Throwable)} which wraps a checked exception in a special runtime exception.
94+
* It is special because framework strips it when chaining exception across logical process boundaries. In this example
95+
* IOException is directly attached to ActivityFailureException besides being wrapped when rethrown.
96+
* </p>
97+
*/
98+
public class HelloException {
99+
100+
private static final String TASK_LIST = "HelloChild";
101+
102+
public interface GreetingWorkflow {
103+
@WorkflowMethod
104+
String getGreeting(String name);
105+
}
106+
107+
/**
108+
* Activity interface is just a POJI
109+
*/
110+
public interface GreetingChild {
111+
@WorkflowMethod
112+
String composeGreeting(String greeting, String name);
113+
}
114+
115+
public interface GreetingActivities {
116+
String composeGreeting(String greeting, String name);
117+
}
118+
119+
/**
120+
* GreetingWorkflow implementation that calls GreetingsActivities#printIt.
121+
*/
122+
public static class GreetingWorkflowImpl implements GreetingWorkflow {
123+
124+
@Override
125+
public String getGreeting(String name) {
126+
GreetingChild child = Workflow.newChildWorkflowStub(GreetingChild.class);
127+
return child.composeGreeting("Hello", name);
128+
}
129+
}
130+
131+
/**
132+
* Child workflow implementation.
133+
* Workflow implementation must always be public for the Cadence to be able to create instances.
134+
*/
135+
public static class GreetingChildImpl implements GreetingChild {
136+
private final GreetingActivities activities = Workflow.newActivityStub(
137+
GreetingActivities.class,
138+
new ActivityOptions.Builder().setScheduleToCloseTimeoutSeconds(10).build());
139+
140+
@Override
141+
public String composeGreeting(String greeting, String name) {
142+
return activities.composeGreeting(greeting, name);
143+
}
144+
}
145+
146+
private static class GreetingActivitiesImpl implements GreetingActivities {
147+
@Override
148+
public String composeGreeting(String greeting, String name) {
149+
try {
150+
throw new IOException(greeting + " " + name + "!");
151+
} catch (IOException e) {
152+
throw Workflow.throwWrapped(e);
153+
}
154+
}
155+
}
156+
157+
public static void main(String[] args) {
158+
BasicConfigurator.configure();
159+
Logger.getRootLogger().setLevel(Level.WARN);
160+
161+
Worker worker = new Worker(DOMAIN, TASK_LIST);
162+
worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class, GreetingChildImpl.class);
163+
worker.registerActivitiesImplementations(new GreetingActivitiesImpl());
164+
worker.start();
165+
166+
WorkflowClient workflowClient = WorkflowClient.newInstance(DOMAIN);
167+
WorkflowOptions workflowOptions = new WorkflowOptions.Builder()
168+
.setTaskList(TASK_LIST)
169+
.setExecutionStartToCloseTimeoutSeconds(30)
170+
.build();
171+
GreetingWorkflow workflow = workflowClient.newWorkflowStub(GreetingWorkflow.class,
172+
workflowOptions);
173+
try {
174+
workflow.getGreeting("World");
175+
throw new IllegalStateException("unreachable");
176+
} catch (WorkflowException e) {
177+
Throwable cause = Throwables.getRootCause(e);
178+
// prints "Hello World!"
179+
System.out.println(cause.getMessage());
180+
System.out.println("\nStack Trace:\n" + Throwables.getStackTraceAsString(e));
181+
}
182+
System.exit(0);
183+
}
184+
}

0 commit comments

Comments
 (0)