Skip to content

Commit 47e520b

Browse files
Add cancellation sample (#46)
1 parent 0351c61 commit 47e520b

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
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+
18+
package com.uber.cadence.samples.hello;
19+
20+
import static com.uber.cadence.samples.common.SampleConstants.DOMAIN;
21+
22+
import com.uber.cadence.activity.ActivityMethod;
23+
import com.uber.cadence.client.WorkflowClient;
24+
import com.uber.cadence.client.WorkflowClientOptions;
25+
import com.uber.cadence.client.WorkflowOptions;
26+
import com.uber.cadence.client.WorkflowStub;
27+
import com.uber.cadence.serviceclient.ClientOptions;
28+
import com.uber.cadence.serviceclient.WorkflowServiceTChannel;
29+
import com.uber.cadence.worker.Worker;
30+
import com.uber.cadence.worker.WorkerFactory;
31+
import com.uber.cadence.workflow.CancellationScope;
32+
import com.uber.cadence.workflow.Workflow;
33+
import com.uber.cadence.workflow.WorkflowMethod;
34+
import java.time.Duration;
35+
import java.util.ArrayList;
36+
import java.util.List;
37+
import java.util.concurrent.CancellationException;
38+
39+
/**
40+
* Demonstrates triggering an activity in response to a cancellation request. Requires a local
41+
* instance of Cadence server to be running.
42+
*/
43+
public class HelloCancellation {
44+
45+
static final String TASK_LIST = "HelloCancellation";
46+
47+
/** Workflow interface has to have at least one method annotated with @WorkflowMethod. */
48+
public interface GreetingWorkflow {
49+
/** @return greeting string */
50+
@WorkflowMethod(executionStartToCloseTimeoutSeconds = 30, taskList = TASK_LIST)
51+
String getGreeting(String name);
52+
}
53+
54+
/** Activity interface is just a POJI. */
55+
public interface GreetingActivities {
56+
@ActivityMethod(scheduleToCloseTimeoutSeconds = 2)
57+
String composeGreeting(String greeting, String name);
58+
59+
@ActivityMethod(scheduleToCloseTimeoutSeconds = 2)
60+
String sayGoodbye(String name);
61+
}
62+
63+
/** GreetingWorkflow implementation that calls GreetingsActivities#composeGreeting. */
64+
public static class GreetingWorkflowImpl implements GreetingWorkflow {
65+
66+
/**
67+
* Activity stub implements activity interface and proxies calls to it to Cadence activity
68+
* invocations. Because activities are reentrant, only a single stub can be used for multiple
69+
* activity invocations.
70+
*/
71+
private final GreetingActivities activities =
72+
Workflow.newActivityStub(GreetingActivities.class);
73+
74+
@Override
75+
public String getGreeting(String name) {
76+
try {
77+
final String result = activities.composeGreeting("Hello", name);
78+
Workflow.sleep(Duration.ofDays(10));
79+
return result;
80+
// This exception is thrown when a cancellation is requested on the current workflow
81+
} catch (CancellationException e) {
82+
/**
83+
* Any call to an activity or a child workflow after the workflow is cancelled is going to
84+
* fail immediately with the CancellationException. the DetachedCancellationScope doesn't
85+
* inherit its cancellation status from the enclosing scope. Thus it allows running a
86+
* cleanup activity even if the workflow cancellation was requested.
87+
*/
88+
CancellationScope scope =
89+
Workflow.newDetachedCancellationScope(() -> activities.sayGoodbye(name));
90+
scope.run();
91+
throw e;
92+
}
93+
}
94+
}
95+
96+
static class GreetingActivitiesImpl implements GreetingActivities {
97+
98+
private final List<String> invocations = new ArrayList<>();
99+
100+
@Override
101+
public String composeGreeting(String greeting, String name) {
102+
invocations.add("composeGreeting");
103+
return greeting + " " + name + "!";
104+
}
105+
106+
@Override
107+
public String sayGoodbye(String name) {
108+
invocations.add("sayGoodbye");
109+
return "Goodbye " + name + "!";
110+
}
111+
112+
List<String> getInvocations() {
113+
return invocations;
114+
}
115+
}
116+
117+
public static void main(String[] args) {
118+
// Get a new client
119+
// NOTE: to set a different options, you can do like this:
120+
// ClientOptions.newBuilder().setRpcTimeout(5 * 1000).build();
121+
WorkflowClient workflowClient =
122+
WorkflowClient.newInstance(
123+
new WorkflowServiceTChannel(ClientOptions.defaultInstance()),
124+
WorkflowClientOptions.newBuilder().setDomain(DOMAIN).build());
125+
// Get worker to poll the task list.
126+
WorkerFactory factory = WorkerFactory.newInstance(workflowClient);
127+
Worker worker = factory.newWorker(TASK_LIST);
128+
// Workflows are stateful. So you need a type to create instances.
129+
worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class);
130+
// Activities are stateless and thread safe. So a shared instance is used.
131+
// A shared instance is used to show activity invocations.
132+
GreetingActivitiesImpl activities = new GreetingActivitiesImpl();
133+
worker.registerActivitiesImplementations(activities);
134+
// Start listening to the workflow and activity task lists.
135+
factory.start();
136+
137+
WorkflowOptions workflowOptions =
138+
new WorkflowOptions.Builder()
139+
.setTaskList(HelloCancellation.TASK_LIST)
140+
.setExecutionStartToCloseTimeout(Duration.ofDays(30))
141+
.build();
142+
// NOTE: strongly typed workflow stub doesn't cancel method.
143+
WorkflowStub client =
144+
workflowClient.newUntypedWorkflowStub("GreetingWorkflow::getGreeting", workflowOptions);
145+
146+
client.start("World");
147+
148+
// issue cancellation request. This will trigger a CancellationException on the workflow.
149+
client.cancel();
150+
151+
try {
152+
client.getResult(String.class);
153+
} catch (CancellationException ignored) {
154+
System.out.println("workflow cancelled. Cancellation exception thrown");
155+
}
156+
157+
System.out.println(activities.getInvocations());
158+
System.exit(0);
159+
}
160+
}

0 commit comments

Comments
 (0)