Skip to content

Commit c215a78

Browse files
authored
Worker / Build Id versioning (#1786)
Implement new worker build id based versioning feature
1 parent 94424c8 commit c215a78

36 files changed

+1046
-122
lines changed

docker/buildkite/dynamicconfig/development.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ system.forceSearchAttributesCacheRefreshOnRead:
22
- value: true
33
system.enableActivityEagerExecution:
44
- value: true
5-
constraints: {}
65
system.enableEagerWorkflowStart:
76
- value: true
8-
constraints: {}
97
frontend.enableUpdateWorkflowExecution:
108
- value: true
11-
constraints: {}
129
frontend.enableUpdateWorkflowExecutionAsyncAccepted:
1310
- value: true
14-
constraints: { }
11+
frontend.workerVersioningWorkflowAPIs:
12+
- value: true
13+
frontend.workerVersioningDataAPIs:
14+
- value: true

temporal-sdk/src/main/java/io/temporal/activity/ActivityOptions.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.temporal.client.WorkflowClientOptions;
2525
import io.temporal.common.MethodRetry;
2626
import io.temporal.common.RetryOptions;
27+
import io.temporal.common.VersioningIntent;
2728
import io.temporal.common.context.ContextPropagator;
2829
import io.temporal.failure.CanceledFailure;
2930
import java.time.Duration;
@@ -62,6 +63,7 @@ public static final class Builder {
6263
private List<ContextPropagator> contextPropagators;
6364
private ActivityCancellationType cancellationType;
6465
private boolean disableEagerExecution;
66+
private VersioningIntent versioningIntent;
6567

6668
private Builder() {}
6769

@@ -78,6 +80,7 @@ private Builder(ActivityOptions options) {
7880
this.scheduleToStartTimeout = options.scheduleToStartTimeout;
7981
this.cancellationType = options.cancellationType;
8082
this.disableEagerExecution = options.disableEagerExecution;
83+
this.versioningIntent = options.versioningIntent;
8184
}
8285

8386
/**
@@ -231,6 +234,15 @@ public Builder setDisableEagerExecution(boolean disableEagerExecution) {
231234
return this;
232235
}
233236

237+
/**
238+
* Specifies whether this activity should run on a worker with a compatible Build Id or not. See
239+
* the variants of {@link VersioningIntent}.
240+
*/
241+
public Builder setVersioningIntent(VersioningIntent versioningIntent) {
242+
this.versioningIntent = versioningIntent;
243+
return this;
244+
}
245+
234246
public Builder mergeActivityOptions(ActivityOptions override) {
235247
if (override == null) {
236248
return this;
@@ -259,6 +271,9 @@ public Builder mergeActivityOptions(ActivityOptions override) {
259271
} else if (override.contextPropagators != null) {
260272
this.contextPropagators.addAll(override.contextPropagators);
261273
}
274+
if (override.versioningIntent != VersioningIntent.VERSIONING_INTENT_UNSPECIFIED) {
275+
this.versioningIntent = override.versioningIntent;
276+
}
262277
return this;
263278
}
264279

@@ -280,7 +295,8 @@ public ActivityOptions build() {
280295
retryOptions,
281296
contextPropagators,
282297
cancellationType,
283-
disableEagerExecution);
298+
disableEagerExecution,
299+
versioningIntent);
284300
}
285301

286302
public ActivityOptions validateAndBuildWithDefaults() {
@@ -293,7 +309,10 @@ public ActivityOptions validateAndBuildWithDefaults() {
293309
retryOptions,
294310
contextPropagators,
295311
cancellationType == null ? ActivityCancellationType.TRY_CANCEL : cancellationType,
296-
disableEagerExecution);
312+
disableEagerExecution,
313+
versioningIntent == null
314+
? VersioningIntent.VERSIONING_INTENT_UNSPECIFIED
315+
: versioningIntent);
297316
}
298317
}
299318

@@ -306,6 +325,7 @@ public ActivityOptions validateAndBuildWithDefaults() {
306325
private final List<ContextPropagator> contextPropagators;
307326
private final ActivityCancellationType cancellationType;
308327
private final boolean disableEagerExecution;
328+
private final VersioningIntent versioningIntent;
309329

310330
private ActivityOptions(
311331
Duration heartbeatTimeout,
@@ -316,7 +336,8 @@ private ActivityOptions(
316336
RetryOptions retryOptions,
317337
List<ContextPropagator> contextPropagators,
318338
ActivityCancellationType cancellationType,
319-
boolean disableEagerExecution) {
339+
boolean disableEagerExecution,
340+
VersioningIntent versioningIntent) {
320341
this.heartbeatTimeout = heartbeatTimeout;
321342
this.scheduleToStartTimeout = scheduleToStartTimeout;
322343
this.scheduleToCloseTimeout = scheduleToCloseTimeout;
@@ -326,6 +347,7 @@ private ActivityOptions(
326347
this.contextPropagators = contextPropagators;
327348
this.cancellationType = cancellationType;
328349
this.disableEagerExecution = disableEagerExecution;
350+
this.versioningIntent = versioningIntent;
329351
}
330352

331353
/**
@@ -388,6 +410,13 @@ public boolean isEagerExecutionDisabled() {
388410
return disableEagerExecution;
389411
}
390412

413+
/**
414+
* @see ActivityOptions.Builder#setVersioningIntent(VersioningIntent)
415+
*/
416+
public VersioningIntent getVersioningIntent() {
417+
return versioningIntent;
418+
}
419+
391420
public Builder toBuilder() {
392421
return new Builder(this);
393422
}
@@ -405,7 +434,8 @@ public boolean equals(Object o) {
405434
&& Objects.equal(taskQueue, that.taskQueue)
406435
&& Objects.equal(retryOptions, that.retryOptions)
407436
&& Objects.equal(contextPropagators, that.contextPropagators)
408-
&& disableEagerExecution == that.disableEagerExecution;
437+
&& disableEagerExecution == that.disableEagerExecution
438+
&& versioningIntent == that.versioningIntent;
409439
}
410440

411441
@Override
@@ -419,7 +449,8 @@ public int hashCode() {
419449
retryOptions,
420450
contextPropagators,
421451
cancellationType,
422-
disableEagerExecution);
452+
disableEagerExecution,
453+
versioningIntent);
423454
}
424455

425456
@Override
@@ -444,6 +475,8 @@ public String toString() {
444475
+ cancellationType
445476
+ ", disableEagerExecution="
446477
+ disableEagerExecution
478+
+ ", versioningIntent="
479+
+ versioningIntent
447480
+ '}';
448481
}
449482
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.client;
22+
23+
import io.temporal.api.workflowservice.v1.UpdateWorkerBuildIdCompatibilityRequest;
24+
import io.temporal.common.Experimental;
25+
import javax.annotation.Nonnull;
26+
27+
/**
28+
* The implementations of this class can be passed as parameters to {@link
29+
* WorkflowClient#updateWorkerBuildIdCompatability(String, BuildIdOperation)}
30+
*
31+
* <p>See each public static method to learn about and construct the available operations.
32+
*/
33+
@Experimental
34+
public abstract class BuildIdOperation {
35+
private BuildIdOperation() {}
36+
37+
abstract void augmentBuilder(UpdateWorkerBuildIdCompatibilityRequest.Builder builder);
38+
39+
/**
40+
* This operation adds a new Build Id into a new set, which will be used as the default set for
41+
* the queue. This means all new workflows will start on this Build Id.
42+
*
43+
* @param buildId The Build Id to add as the new overall default.
44+
*/
45+
public static BuildIdOperation newIdInNewDefaultSet(@Nonnull String buildId) {
46+
return new NewIdInNewDefaultSet(buildId);
47+
}
48+
49+
/**
50+
* This operation adds a new Build Id into an existing compatible set. The newly added ID becomes
51+
* the default for that compatible set, and thus new workflow tasks for workflows which have been
52+
* executing on workers in that set will now start on this new Build Id.
53+
*
54+
* @param buildId The Build Id to add to an existing compatible set.
55+
* @param existingCompatibleBuildId A Build Id which must already be defined on the task queue,
56+
* and is used to find the compatible set to add the new ID to.
57+
* @param makeSetDefault If set to true, the targeted set will also be promoted to become the
58+
* overall default set for the queue.
59+
*/
60+
public static BuildIdOperation newCompatibleVersion(
61+
@Nonnull String buildId, @Nonnull String existingCompatibleBuildId, boolean makeSetDefault) {
62+
return new NewCompatibleVersion(buildId, existingCompatibleBuildId, makeSetDefault);
63+
}
64+
65+
/**
66+
* Performs {@link #newCompatibleVersion(String, String, boolean)}, with `makeSetDefault` set to
67+
* false.
68+
*/
69+
public static BuildIdOperation newCompatibleVersion(
70+
@Nonnull String buildId, @Nonnull String existingCompatibleBuildId) {
71+
return newCompatibleVersion(buildId, existingCompatibleBuildId, false);
72+
}
73+
74+
/**
75+
* This operation promotes a set to become the overall default set for the queue.
76+
*
77+
* @param buildId An existing Build Id which is used to find the set to be promoted.
78+
*/
79+
public static BuildIdOperation promoteSetByBuildId(@Nonnull String buildId) {
80+
return new PromoteSetByBuildId(buildId);
81+
}
82+
83+
/**
84+
* This operation promotes a Build Id inside some compatible set to become the default ID in that
85+
* set.
86+
*
87+
* @param buildId An existing Build Id which will be promoted within its compatible set.
88+
*/
89+
public static BuildIdOperation promoteBuildIdWithinSet(@Nonnull String buildId) {
90+
return new PromoteBuildIdWithinSet(buildId);
91+
}
92+
93+
/**
94+
* This operation merges two sets into one set, thus declaring all the Build Ids in both as
95+
* compatible with one another. The default of the primary set is maintained as the merged set's
96+
* overall default.
97+
*
98+
* @param primaryBuildId A Build Id which is used to find the primary set to be merged.
99+
* @param secondaryBuildId A Build Id which is used to find the secondary set to be merged.
100+
*/
101+
public static BuildIdOperation mergeSets(
102+
@Nonnull String primaryBuildId, @Nonnull String secondaryBuildId) {
103+
return new MergeSets(primaryBuildId, secondaryBuildId);
104+
}
105+
106+
private static class NewIdInNewDefaultSet extends BuildIdOperation {
107+
private final String buildId;
108+
109+
public NewIdInNewDefaultSet(String buildId) {
110+
this.buildId = buildId;
111+
}
112+
113+
@Override
114+
void augmentBuilder(UpdateWorkerBuildIdCompatibilityRequest.Builder builder) {
115+
builder.setAddNewBuildIdInNewDefaultSet(buildId);
116+
}
117+
}
118+
119+
private static class NewCompatibleVersion extends BuildIdOperation {
120+
private final String buildId;
121+
private final String existingCompatibleBuildId;
122+
private final boolean makeSetDefault;
123+
124+
public NewCompatibleVersion(
125+
String buildId, String existingCompatibleBuildId, boolean makeSetDefault) {
126+
this.buildId = buildId;
127+
this.existingCompatibleBuildId = existingCompatibleBuildId;
128+
this.makeSetDefault = makeSetDefault;
129+
}
130+
131+
@Override
132+
void augmentBuilder(UpdateWorkerBuildIdCompatibilityRequest.Builder builder) {
133+
builder.setAddNewCompatibleBuildId(
134+
UpdateWorkerBuildIdCompatibilityRequest.AddNewCompatibleVersion.newBuilder()
135+
.setNewBuildId(buildId)
136+
.setExistingCompatibleBuildId(existingCompatibleBuildId)
137+
.setMakeSetDefault(makeSetDefault)
138+
.build());
139+
}
140+
}
141+
142+
private static class PromoteSetByBuildId extends BuildIdOperation {
143+
private final String buildId;
144+
145+
public PromoteSetByBuildId(String buildId) {
146+
this.buildId = buildId;
147+
}
148+
149+
@Override
150+
void augmentBuilder(UpdateWorkerBuildIdCompatibilityRequest.Builder builder) {
151+
builder.setPromoteSetByBuildId(buildId);
152+
}
153+
}
154+
155+
private static class PromoteBuildIdWithinSet extends BuildIdOperation {
156+
private final String buildId;
157+
158+
public PromoteBuildIdWithinSet(String buildId) {
159+
this.buildId = buildId;
160+
}
161+
162+
@Override
163+
void augmentBuilder(UpdateWorkerBuildIdCompatibilityRequest.Builder builder) {
164+
builder.setPromoteBuildIdWithinSet(buildId);
165+
}
166+
}
167+
168+
private static class MergeSets extends BuildIdOperation {
169+
private final String primaryBuildId;
170+
private final String secondaryBuildId;
171+
172+
public MergeSets(String primaryBuildId, String secondaryBuildId) {
173+
this.primaryBuildId = primaryBuildId;
174+
this.secondaryBuildId = secondaryBuildId;
175+
}
176+
177+
@Override
178+
void augmentBuilder(UpdateWorkerBuildIdCompatibilityRequest.Builder builder) {
179+
builder.setMergeSets(
180+
UpdateWorkerBuildIdCompatibilityRequest.MergeSets.newBuilder()
181+
.setPrimarySetBuildId(primaryBuildId)
182+
.setSecondarySetBuildId(secondaryBuildId)
183+
.build());
184+
}
185+
}
186+
}

0 commit comments

Comments
 (0)