Skip to content

Commit ea83af1

Browse files
Port go-client changes to support the enhanced versioning feature
1 parent daa6211 commit ea83af1

File tree

11 files changed

+519
-7
lines changed

11 files changed

+519
-7
lines changed

src/main/java/com/uber/cadence/internal/replay/ClockDecisionContext.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ private void handleVersionMarker(MarkerRecordedEventAttributes attributes) {
320320

321321
GetVersionResult getVersion(
322322
String changeId, DataConverter converter, int minSupported, int maxSupported) {
323+
return getVersion(changeId, converter, minSupported, maxSupported, GetVersionOptions.newBuilder().build());
324+
}
325+
326+
GetVersionResult getVersion(
327+
String changeId, DataConverter converter, int minSupported, int maxSupported, GetVersionOptions options) {
323328
Predicate<MarkerRecordedEventAttributes> changeIdEquals =
324329
(attributes) -> {
325330
MarkerHandler.MarkerInterface markerData =
@@ -328,6 +333,9 @@ GetVersionResult getVersion(
328333
};
329334
decisions.addAllMissingVersionMarker(true, Optional.of(changeIdEquals));
330335

336+
// Determine which version to use based on options
337+
int versionToUse = determineVersionToUse(minSupported, maxSupported, options);
338+
331339
final MarkerHandler.HandleResult result =
332340
versionHandler.handle(
333341
changeId,
@@ -336,14 +344,14 @@ GetVersionResult getVersion(
336344
if (stored.isPresent()) {
337345
return Optional.empty();
338346
}
339-
return Optional.of(converter.toData(maxSupported));
347+
return Optional.of(converter.toData(versionToUse));
340348
});
341349

342350
final boolean isNewlyAdded = result.isNewlyStored();
343351
Map<String, Object> searchAttributesForChangeVersion = null;
344352
if (isNewlyAdded) {
345353
searchAttributesForChangeVersion =
346-
createSearchAttributesForChangeVersion(changeId, maxSupported, versionMap);
354+
createSearchAttributesForChangeVersion(changeId, versionToUse, versionMap);
347355
}
348356

349357
Integer version = versionMap.get(changeId);
@@ -361,6 +369,22 @@ GetVersionResult getVersion(
361369
return new GetVersionResult(version, isNewlyAdded, searchAttributesForChangeVersion);
362370
}
363371

372+
private int determineVersionToUse(int minSupported, int maxSupported, GetVersionOptions options) {
373+
if (isReplaying()) {
374+
return WorkflowInternal.DEFAULT_VERSION;
375+
}
376+
377+
if (options.getCustomVersion().isPresent()) {
378+
return options.getCustomVersion().get();
379+
}
380+
381+
if (options.isUseMinVersion()) {
382+
return minSupported;
383+
}
384+
385+
return maxSupported;
386+
}
387+
364388
private void validateVersion(String changeID, int version, int minSupported, int maxSupported) {
365389
if ((version < minSupported || version > maxSupported)
366390
&& version != WorkflowInternal.DEFAULT_VERSION) {

src/main/java/com/uber/cadence/internal/replay/DecisionContext.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ Optional<byte[]> mutableSideEffect(
194194
*/
195195
int getVersion(String changeID, DataConverter dataConverter, int minSupported, int maxSupported);
196196

197+
/**
198+
* Enhanced version of getVersion with additional options for version control.
199+
*
200+
* @param changeID identifier of a particular change
201+
* @param dataConverter data converter for serialization
202+
* @param minSupported min version supported for the change
203+
* @param maxSupported max version supported for the change
204+
* @param options version control options
205+
* @return version
206+
*/
207+
int getVersion(String changeID, DataConverter dataConverter, int minSupported, int maxSupported, GetVersionOptions options);
208+
197209
Random newRandom();
198210

199211
/** @return scope to be used for metrics reporting. */

src/main/java/com/uber/cadence/internal/replay/DecisionContextImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,19 @@ public int getVersion(
302302
return results.getVersion();
303303
}
304304

305+
@Override
306+
public int getVersion(
307+
String changeID, DataConverter converter, int minSupported, int maxSupported, GetVersionOptions options) {
308+
final ClockDecisionContext.GetVersionResult results =
309+
workflowClock.getVersion(changeID, converter, minSupported, maxSupported, options);
310+
if (results.shouldUpdateCadenceChangeVersion()) {
311+
upsertSearchAttributes(
312+
InternalUtils.convertMapToSearchAttributes(
313+
results.getSearchAttributesForChangeVersion()));
314+
}
315+
return results.getVersion();
316+
}
317+
305318
@Override
306319
public long currentTimeMillis() {
307320
return workflowClock.currentTimeMillis();

src/main/java/com/uber/cadence/internal/sync/SyncDecisionContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,11 @@ public int getVersion(String changeID, int minSupported, int maxSupported) {
620620
return context.getVersion(changeID, converter, minSupported, maxSupported);
621621
}
622622

623+
@Override
624+
public int getVersion(String changeID, int minSupported, int maxSupported, GetVersionOptions options) {
625+
return context.getVersion(changeID, converter, minSupported, maxSupported, options);
626+
}
627+
623628
void fireTimers() {
624629
timers.fireTimers(context.currentTimeMillis());
625630
}

src/main/java/com/uber/cadence/internal/sync/WorkflowInternal.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,19 @@ public static int getVersion(String changeID, int minSupported, int maxSupported
253253
return getWorkflowInterceptor().getVersion(changeID, minSupported, maxSupported);
254254
}
255255

256+
/**
257+
* Enhanced version of getVersion with additional options for version control.
258+
*
259+
* @param changeID identifier of a particular change
260+
* @param minSupported min version supported for the change
261+
* @param maxSupported max version supported for the change
262+
* @param options version control options
263+
* @return version
264+
*/
265+
public static int getVersion(String changeID, int minSupported, int maxSupported, GetVersionOptions options) {
266+
return getWorkflowInterceptor().getVersion(changeID, minSupported, maxSupported, options);
267+
}
268+
256269
public static <U> Promise<List<U>> promiseAllOf(Collection<Promise<U>> promises) {
257270
return new AllOfPromise<>(promises);
258271
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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.workflow;
19+
20+
import java.util.Optional;
21+
22+
/**
23+
* Options for configuring GetVersion behavior.
24+
* This class provides a builder pattern for configuring version control options.
25+
*
26+
* <p>Example usage:
27+
* <pre><code>
28+
* // Force a specific version
29+
* GetVersionOptions options = GetVersionOptions.newBuilder()
30+
* .executeWithVersion(2)
31+
* .build();
32+
*
33+
* // Use minimum supported version
34+
* GetVersionOptions options = GetVersionOptions.newBuilder()
35+
* .executeWithMinVersion()
36+
* .build();
37+
* </code></pre>
38+
*/
39+
public final class GetVersionOptions {
40+
private final Optional<Integer> customVersion;
41+
private final boolean useMinVersion;
42+
43+
private GetVersionOptions(Optional<Integer> customVersion, boolean useMinVersion) {
44+
this.customVersion = customVersion;
45+
this.useMinVersion = useMinVersion;
46+
}
47+
48+
/**
49+
* Returns the custom version if specified, otherwise empty.
50+
*/
51+
public Optional<Integer> getCustomVersion() {
52+
return customVersion;
53+
}
54+
55+
/**
56+
* Returns true if the minimum version should be used instead of maximum version.
57+
*/
58+
public boolean isUseMinVersion() {
59+
return useMinVersion;
60+
}
61+
62+
/**
63+
* Creates a new builder for GetVersionOptions.
64+
*/
65+
public static Builder newBuilder() {
66+
return new Builder();
67+
}
68+
69+
/**
70+
* Builder for GetVersionOptions.
71+
*/
72+
public static class Builder {
73+
private Optional<Integer> customVersion = Optional.empty();
74+
private boolean useMinVersion = false;
75+
76+
/**
77+
* Forces a specific version to be returned when executed for the first time,
78+
* instead of returning maxSupported version.
79+
*
80+
* @param version the specific version to use
81+
* @return this builder
82+
*/
83+
public Builder executeWithVersion(int version) {
84+
this.customVersion = Optional.of(version);
85+
return this;
86+
}
87+
88+
/**
89+
* Makes GetVersion return minSupported version when executed for the first time,
90+
* instead of returning maxSupported version.
91+
*
92+
* @return this builder
93+
*/
94+
public Builder executeWithMinVersion() {
95+
this.useMinVersion = true;
96+
return this;
97+
}
98+
99+
/**
100+
* Builds the GetVersionOptions instance.
101+
*
102+
* @return the configured GetVersionOptions
103+
*/
104+
public GetVersionOptions build() {
105+
return new GetVersionOptions(customVersion, useMinVersion);
106+
}
107+
}
108+
}

src/main/java/com/uber/cadence/workflow/Workflow.java

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@
353353
* executed in parallel.
354354
* <li>Do not call any non deterministic functions like non seeded random or {@link
355355
* UUID#randomUUID()} directly form the workflow code. Always do this in activities.
356-
* <li>Dont perform any IO or service calls as they are not usually deterministic. Use activities
356+
* <li>Don't perform any IO or service calls as they are not usually deterministic. Use activities
357357
* for this.
358358
* <li>Only use {@link #currentTimeMillis()} to get the current time inside a workflow.
359359
* <li>Do not use native Java {@link Thread} or any other multi-threaded classes like {@link
@@ -369,7 +369,7 @@
369369
* <li>Use {@link WorkflowQueue} instead of {@link java.util.concurrent.BlockingQueue}.
370370
* <li>Don't change workflow code when there are open workflows. The ability to do updates through
371371
* visioning is TBD.
372-
* <li>Dont access configuration APIs directly from a workflow because changes in the
372+
* <li>Don't access configuration APIs directly from a workflow because changes in the
373373
* configuration might affect a workflow execution path. Pass it as an argument to a workflow
374374
* function or use an activity to load it.
375375
* </ul>
@@ -1123,15 +1123,15 @@ public static <R> R mutableSideEffect(
11231123
* </code></pre>
11241124
*
11251125
* The reason to keep it is: 1) it ensures that if there is older version execution still running,
1126-
* it will fail here and not proceed; 2) if you ever need to make more changes for fooChange,
1126+
* it will fail here and not proceed; 2) if you ever need to make more changes for "fooChange",
11271127
* for example change activity3 to activity4, you just need to update the maxVersion from 2 to 3.
11281128
*
11291129
* <p>Note that, you only need to preserve the first call to GetVersion() for each changeID. All
11301130
* subsequent call to GetVersion() with same changeID are safe to remove. However, if you really
11311131
* want to get rid of the first GetVersion() call as well, you can do so, but you need to make
1132-
* sure: 1) all older version executions are completed; 2) you can no longer use fooChange as
1132+
* sure: 1) all older version executions are completed; 2) you can no longer use "fooChange" as
11331133
* changeID. If you ever need to make changes to that same part, you would need to use a different
1134-
* changeID like fooChange-fix2, and start minVersion from DefaultVersion again.
1134+
* changeID like "fooChange-fix2", and start minVersion from DefaultVersion again.
11351135
*
11361136
* @param changeID identifier of a particular change. All calls to getVersion that share a
11371137
* changeID are guaranteed to return the same version number. Use this to perform multiple
@@ -1144,6 +1144,63 @@ public static int getVersion(String changeID, int minSupported, int maxSupported
11441144
return WorkflowInternal.getVersion(changeID, minSupported, maxSupported);
11451145
}
11461146

1147+
/**
1148+
* Enhanced version of {@code getVersion} with additional options for version control.
1149+
* This method provides more granular control over version execution and enables safer deployment strategies.
1150+
*
1151+
* <p>Example usage with custom version:
1152+
* <pre><code>
1153+
* int version = Workflow.getVersion("changeId", 1, 3,
1154+
* GetVersionOptions.newBuilder().executeWithVersion(2).build());
1155+
* </code></pre>
1156+
*
1157+
* <p>Example usage with minimum version:
1158+
* <pre><code>
1159+
* int version = Workflow.getVersion("changeId", 1, 3,
1160+
* GetVersionOptions.newBuilder().executeWithMinVersion().build());
1161+
* </code></pre>
1162+
*
1163+
* @param changeID identifier of a particular change
1164+
* @param minSupported min version supported for the change
1165+
* @param maxSupported max version supported for the change
1166+
* @param options version control options
1167+
* @return version
1168+
*/
1169+
public static int getVersion(String changeID, int minSupported, int maxSupported, GetVersionOptions options) {
1170+
return WorkflowInternal.getVersion(changeID, minSupported, maxSupported, options);
1171+
}
1172+
1173+
/**
1174+
* Convenience method that forces a specific version to be returned when executed for the first time.
1175+
*
1176+
* @param changeID identifier of a particular change
1177+
* @param minSupported min version supported for the change
1178+
* @param maxSupported max version supported for the change
1179+
* @param customVersion the specific version to use
1180+
* @return version
1181+
*/
1182+
public static int getVersionWithCustomVersion(String changeID, int minSupported, int maxSupported, int customVersion) {
1183+
GetVersionOptions options = GetVersionOptions.newBuilder()
1184+
.executeWithVersion(customVersion)
1185+
.build();
1186+
return getVersion(changeID, minSupported, maxSupported, options);
1187+
}
1188+
1189+
/**
1190+
* Convenience method that makes GetVersion return minSupported version when executed for the first time.
1191+
*
1192+
* @param changeID identifier of a particular change
1193+
* @param minSupported min version supported for the change
1194+
* @param maxSupported max version supported for the change
1195+
* @return version
1196+
*/
1197+
public static int getVersionWithMinVersion(String changeID, int minSupported, int maxSupported) {
1198+
GetVersionOptions options = GetVersionOptions.newBuilder()
1199+
.executeWithMinVersion()
1200+
.build();
1201+
return getVersion(changeID, minSupported, maxSupported, options);
1202+
}
1203+
11471204
/**
11481205
* Get scope for reporting business metrics in workflow logic. This should be used instead of
11491206
* creating new metrics scopes as it is able to dedup metrics during replay.

src/main/java/com/uber/cadence/workflow/WorkflowInterceptor.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,17 @@ <R> R mutableSideEffect(
127127

128128
int getVersion(String changeID, int minSupported, int maxSupported);
129129

130+
/**
131+
* Enhanced version of getVersion with additional options for version control.
132+
*
133+
* @param changeID identifier of a particular change
134+
* @param minSupported min version supported for the change
135+
* @param maxSupported max version supported for the change
136+
* @param options version control options
137+
* @return version
138+
*/
139+
int getVersion(String changeID, int minSupported, int maxSupported, GetVersionOptions options);
140+
130141
void continueAsNew(
131142
Optional<String> workflowType, Optional<ContinueAsNewOptions> options, Object[] args);
132143

src/main/java/com/uber/cadence/workflow/WorkflowInterceptorBase.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ public int getVersion(String changeID, int minSupported, int maxSupported) {
134134
return next.getVersion(changeID, minSupported, maxSupported);
135135
}
136136

137+
@Override
138+
public int getVersion(String changeID, int minSupported, int maxSupported, GetVersionOptions options) {
139+
return next.getVersion(changeID, minSupported, maxSupported, options);
140+
}
141+
137142
@Override
138143
public void continueAsNew(
139144
Optional<String> workflowType, Optional<ContinueAsNewOptions> options, Object[] args) {

0 commit comments

Comments
 (0)