Skip to content

Commit 99aaae0

Browse files
authored
Merge pull request #28 from vancexu/sa
Add example for start workflow with search attributes
2 parents 1373dbe + efa6f97 commit 99aaae0

File tree

2 files changed

+167
-1
lines changed

2 files changed

+167
-1
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ repositories {
3535
dependencies {
3636
errorproneJavac("com.google.errorprone:javac:9+181-r4173-1")
3737
errorprone("com.google.errorprone:error_prone_core:2.3.1")
38-
compile group: 'com.uber.cadence', name: 'cadence-client', version: '2.5.2'
38+
compile group: 'com.uber.cadence', name: 'cadence-client', version: '2.6.0'
3939
compile group: 'commons-configuration', name: 'commons-configuration', version: '1.9'
4040
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
4141
testCompile group: 'junit', name: 'junit', version: '4.12'
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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.DescribeWorkflowExecutionRequest;
23+
import com.uber.cadence.DescribeWorkflowExecutionResponse;
24+
import com.uber.cadence.SearchAttributes;
25+
import com.uber.cadence.WorkflowExecution;
26+
import com.uber.cadence.activity.ActivityMethod;
27+
import com.uber.cadence.client.WorkflowClient;
28+
import com.uber.cadence.client.WorkflowOptions;
29+
import com.uber.cadence.converter.DataConverter;
30+
import com.uber.cadence.converter.JsonDataConverter;
31+
import com.uber.cadence.serviceclient.IWorkflowService;
32+
import com.uber.cadence.serviceclient.WorkflowServiceTChannel;
33+
import com.uber.cadence.worker.Worker;
34+
import com.uber.cadence.workflow.Workflow;
35+
import com.uber.cadence.workflow.WorkflowMethod;
36+
import java.nio.ByteBuffer;
37+
import java.time.LocalDateTime;
38+
import java.time.format.DateTimeFormatter;
39+
import java.util.HashMap;
40+
import java.util.Map;
41+
import java.util.UUID;
42+
43+
public class HelloSearchAttributes {
44+
45+
static final String TASK_LIST = "HelloSearchAttributes";
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 = 10, 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+
60+
/** GreetingWorkflow implementation that calls GreetingsActivities#composeGreeting. */
61+
public static class GreetingWorkflowImpl implements HelloActivity.GreetingWorkflow {
62+
63+
/**
64+
* Activity stub implements activity interface and proxies calls to it to Cadence activity
65+
* invocations. Because activities are reentrant, only a single stub can be used for multiple
66+
* activity invocations.
67+
*/
68+
private final HelloActivity.GreetingActivities activities =
69+
Workflow.newActivityStub(HelloActivity.GreetingActivities.class);
70+
71+
@Override
72+
public String getGreeting(String name) {
73+
// This is a blocking call that returns only after the activity has completed.
74+
return activities.composeGreeting("Hello", name);
75+
}
76+
}
77+
78+
static class GreetingActivitiesImpl implements HelloActivity.GreetingActivities {
79+
@Override
80+
public String composeGreeting(String greeting, String name) {
81+
return greeting + " " + name + "!";
82+
}
83+
}
84+
85+
public static void main(String[] args) {
86+
// Start a worker that hosts both workflow and activity implementations.
87+
Worker.Factory factory = new Worker.Factory(DOMAIN);
88+
Worker worker = factory.newWorker(TASK_LIST);
89+
// Workflows are stateful. So you need a type to create instances.
90+
worker.registerWorkflowImplementationTypes(HelloSearchAttributes.GreetingWorkflowImpl.class);
91+
// Activities are stateless and thread safe. So a shared instance is used.
92+
worker.registerActivitiesImplementations(new HelloSearchAttributes.GreetingActivitiesImpl());
93+
// Start listening to the workflow and activity task lists.
94+
factory.start();
95+
96+
// Start a workflow execution. Usually this is done from another program.
97+
WorkflowClient workflowClient = WorkflowClient.newInstance(DOMAIN);
98+
99+
// Set search attributes in workflowOptions
100+
String workflowID = UUID.randomUUID().toString();
101+
WorkflowOptions workflowOptions =
102+
new WorkflowOptions.Builder()
103+
.setTaskList(TASK_LIST)
104+
.setWorkflowId(workflowID)
105+
.setSearchAttributes(generateSearchAttributes())
106+
.build();
107+
// Get a workflow stub using the same task list the worker uses.
108+
HelloSearchAttributes.GreetingWorkflow workflow =
109+
workflowClient.newWorkflowStub(
110+
HelloSearchAttributes.GreetingWorkflow.class, workflowOptions);
111+
// Execute a workflow waiting for it to complete.
112+
String greeting = workflow.getGreeting("SearchAttributes");
113+
114+
IWorkflowService cadenceService = new WorkflowServiceTChannel();
115+
WorkflowExecution execution = new WorkflowExecution();
116+
execution.setWorkflowId(workflowID);
117+
118+
DescribeWorkflowExecutionRequest request = new DescribeWorkflowExecutionRequest();
119+
request.setDomain(DOMAIN);
120+
request.setExecution(execution);
121+
try {
122+
DescribeWorkflowExecutionResponse resp = cadenceService.DescribeWorkflowExecution(request);
123+
SearchAttributes searchAttributes = resp.workflowExecutionInfo.getSearchAttributes();
124+
String keyword = getKeywordFromSearchAttribute(searchAttributes);
125+
System.out.printf("In workflow we get CustomKeywordField is: %s\n", keyword);
126+
} catch (Exception e) {
127+
System.out.println(e);
128+
}
129+
130+
System.out.println(greeting);
131+
System.exit(0);
132+
}
133+
134+
private static Map<String, Object> generateSearchAttributes() {
135+
Map<String, Object> searchAttributes = new HashMap<>();
136+
searchAttributes.put(
137+
"CustomKeywordField",
138+
"keys"); // each field can also be array such as: String[] keys = {"k1", "k2"};
139+
searchAttributes.put("CustomIntField", 1);
140+
searchAttributes.put("CustomDoubleField", 0.1);
141+
searchAttributes.put("CustomBoolField", true);
142+
searchAttributes.put("CustomDatetimeField", generateDateTimeFieldValue());
143+
searchAttributes.put(
144+
"CustomStringField",
145+
"String field is for text. When query, it will be tokenized for partial match. StringTypeField cannot be used in Order By");
146+
return searchAttributes;
147+
}
148+
149+
// CustomDatetimeField takes string like "2018-07-14T17:45:55.9483536" or
150+
// "2019-01-01T00:00:00-08:00" as value
151+
private static String generateDateTimeFieldValue() {
152+
LocalDateTime currentDateTime = LocalDateTime.now();
153+
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
154+
return currentDateTime.format(formatter);
155+
}
156+
157+
// example for extract value from search attributes
158+
private static String getKeywordFromSearchAttribute(SearchAttributes searchAttributes) {
159+
Map<String, ByteBuffer> map = searchAttributes.getIndexedFields();
160+
ByteBuffer byteBuffer = map.get("CustomKeywordField");
161+
DataConverter dataConverter = JsonDataConverter.getInstance();
162+
final byte[] valueBytes = new byte[byteBuffer.limit() - byteBuffer.position()];
163+
byteBuffer.get(valueBytes, 0, valueBytes.length);
164+
return dataConverter.fromData(valueBytes, String.class, String.class);
165+
}
166+
}

0 commit comments

Comments
 (0)