Skip to content

Commit 1ad1c04

Browse files
Require WaitForStage in StartUpdate (#2088)
1 parent 4eda239 commit 1ad1c04

File tree

8 files changed

+64
-40
lines changed

8 files changed

+64
-40
lines changed

temporal-sdk/src/main/java/io/temporal/client/UpdateOptions.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ public static <T> UpdateOptions.Builder<T> newBuilder(Class<T> resultClass) {
3333
return new UpdateOptions.Builder<T>().setResultClass(resultClass);
3434
}
3535

36-
public static UpdateOptions.Builder newBuilder(UpdateOptions options) {
37-
return new UpdateOptions.Builder(options);
36+
public static <T> UpdateOptions.Builder<T> newBuilder(UpdateOptions<T> options) {
37+
return new UpdateOptions.Builder<T>(options);
3838
}
3939

4040
public static UpdateOptions getDefaultInstance() {
@@ -50,21 +50,21 @@ public static UpdateOptions getDefaultInstance() {
5050
private final String updateName;
5151
private final String updateId;
5252
private final String firstExecutionRunId;
53-
private final WorkflowUpdateStage waitPolicy;
53+
private final WorkflowUpdateStage waitForStage;
5454
private final Class<T> resultClass;
5555
private final Type resultType;
5656

5757
private UpdateOptions(
5858
String updateName,
5959
String updateId,
6060
String firstExecutionRunId,
61-
WorkflowUpdateStage waitPolicy,
61+
WorkflowUpdateStage waitForStage,
6262
Class<T> resultClass,
6363
Type resultType) {
6464
this.updateName = updateName;
6565
this.updateId = updateId;
6666
this.firstExecutionRunId = firstExecutionRunId;
67-
this.waitPolicy = waitPolicy;
67+
this.waitForStage = waitForStage;
6868
this.resultClass = resultClass;
6969
this.resultType = resultType;
7070
}
@@ -81,8 +81,8 @@ public String getFirstExecutionRunId() {
8181
return firstExecutionRunId;
8282
}
8383

84-
public WorkflowUpdateStage getWaitPolicy() {
85-
return waitPolicy;
84+
public WorkflowUpdateStage getWaitForStage() {
85+
return waitForStage;
8686
}
8787

8888
public Class<T> getResultClass() {
@@ -105,15 +105,15 @@ public boolean equals(Object o) {
105105
return Objects.equal(updateName, that.updateName)
106106
&& updateId == that.updateId
107107
&& firstExecutionRunId == that.firstExecutionRunId
108-
&& waitPolicy.equals(that.waitPolicy)
108+
&& waitForStage.equals(that.waitForStage)
109109
&& resultClass.equals(that.resultClass)
110110
&& resultType.equals(that.resultType);
111111
}
112112

113113
@Override
114114
public int hashCode() {
115115
return Objects.hashCode(
116-
updateName, updateId, firstExecutionRunId, waitPolicy, resultClass, resultType);
116+
updateName, updateId, firstExecutionRunId, waitForStage, resultClass, resultType);
117117
}
118118

119119
@Override
@@ -125,8 +125,8 @@ public String toString() {
125125
+ updateId
126126
+ ", firstExecutionRunId="
127127
+ firstExecutionRunId
128-
+ ", waitPolicy="
129-
+ waitPolicy
128+
+ ", waitForStage="
129+
+ waitForStage
130130
+ ", resultClass="
131131
+ resultClass
132132
+ ", resultType='"
@@ -146,13 +146,19 @@ public void validate() {
146146
if (resultClass == null) {
147147
throw new IllegalStateException("resultClass must not be null");
148148
}
149+
if (waitForStage == null) {
150+
throw new IllegalStateException("waitForStage must not be null");
151+
}
152+
if (waitForStage.equals(WorkflowUpdateStage.ADMITTED)) {
153+
throw new IllegalStateException("waitForStage cannot be ADMITTED");
154+
}
149155
}
150156

151157
public static final class Builder<T> {
152158
private String updateName;
153159
private String updateId;
154160
private String firstExecutionRunId;
155-
private WorkflowUpdateStage waitPolicy;
161+
private WorkflowUpdateStage waitForStage;
156162
private Class<T> resultClass;
157163
private Type resultType;
158164

@@ -165,7 +171,7 @@ private Builder(UpdateOptions<T> options) {
165171
this.updateName = options.updateName;
166172
this.updateId = options.updateId;
167173
this.firstExecutionRunId = options.firstExecutionRunId;
168-
this.waitPolicy = options.waitPolicy;
174+
this.waitForStage = options.waitForStage;
169175
this.resultClass = options.resultClass;
170176
this.resultType = options.resultType;
171177
}
@@ -200,16 +206,17 @@ public Builder<T> setFirstExecutionRunId(String firstExecutionRunId) {
200206

201207
/**
202208
* Specifies at what point in the update request life cycles this request should return.
203-
*
204-
* <p>Default value if not set: <b>Accepted</b>
209+
* Required to be set to one of the following values:
205210
*
206211
* <ul>
207212
* <li><b>Accepted</b> Wait for the update to be accepted by the workflow.
208213
* <li><b>Completed</b> Wait for the update to be completed by the workflow.
209214
* </ul>
215+
*
216+
* Admitted is not allowed as a value.
210217
*/
211-
public Builder<T> setWaitPolicy(WorkflowUpdateStage waitPolicy) {
212-
this.waitPolicy = waitPolicy;
218+
public Builder<T> setWaitForStage(WorkflowUpdateStage waitForStage) {
219+
this.waitForStage = waitForStage;
213220
return this;
214221
}
215222

@@ -239,7 +246,7 @@ public UpdateOptions<T> build() {
239246
updateName,
240247
updateId,
241248
firstExecutionRunId == null ? "" : firstExecutionRunId,
242-
waitPolicy == null ? WorkflowUpdateStage.ACCEPTED : waitPolicy,
249+
waitForStage,
243250
resultClass,
244251
resultType == null ? resultClass : resultType);
245252
}

temporal-sdk/src/main/java/io/temporal/client/WorkflowStub.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,20 @@ static <T> WorkflowStub fromTyped(T typed) {
9393

9494
/**
9595
* Asynchronously update a workflow execution by invoking its update handler and returning a
96-
* handle to the update request. Usually a update handler is a method annotated with {@link
96+
* handle to the update request. Usually an update handler is a method annotated with {@link
9797
* io.temporal.workflow.UpdateMethod}.
9898
*
9999
* @param updateName name of the update handler. Usually it is a method name.
100+
* @param waitForStage stage to wait for before returning the update handle. Admitted is not
101+
* allowed as a value.
100102
* @param resultClass class of the update return value
101103
* @param <R> type of the update return value
102104
* @param args update method arguments
103105
* @return update handle that can be used to get the result of the update.
104106
*/
105107
@Experimental
106-
<R> UpdateHandle<R> startUpdate(String updateName, Class<R> resultClass, Object... args);
108+
<R> UpdateHandle<R> startUpdate(
109+
String updateName, WorkflowUpdateStage waitForStage, Class<R> resultClass, Object... args);
107110

108111
/**
109112
* Asynchronously update a workflow execution by invoking its update handler and returning a

temporal-sdk/src/main/java/io/temporal/client/WorkflowStubImpl.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ public <R> R update(String updateName, Class<R> resultClass, Object... args) {
297297
UpdateOptions<R> options =
298298
UpdateOptions.<R>newBuilder()
299299
.setUpdateName(updateName)
300-
.setWaitPolicy(WorkflowUpdateStage.COMPLETED)
300+
.setWaitForStage(WorkflowUpdateStage.COMPLETED)
301301
.setResultClass(resultClass)
302302
.build();
303303
return startUpdate(options, args).getResultAsync().get();
@@ -312,11 +312,12 @@ public <R> R update(String updateName, Class<R> resultClass, Object... args) {
312312
}
313313

314314
@Override
315-
public <R> UpdateHandle<R> startUpdate(String updateName, Class<R> resultClass, Object... args) {
315+
public <R> UpdateHandle<R> startUpdate(
316+
String updateName, WorkflowUpdateStage waitForStage, Class<R> resultClass, Object... args) {
316317
UpdateOptions<R> options =
317318
UpdateOptions.<R>newBuilder()
318319
.setUpdateName(updateName)
319-
.setWaitPolicy(WorkflowUpdateStage.ACCEPTED)
320+
.setWaitForStage(waitForStage)
320321
.setResultClass(resultClass)
321322
.setResultType(resultClass)
322323
.build();
@@ -342,7 +343,7 @@ public <R> UpdateHandle<R> startUpdate(UpdateOptions<R> options, Object... args)
342343
options.getResultType(),
343344
options.getFirstExecutionRunId(),
344345
WaitPolicy.newBuilder()
345-
.setLifecycleStage(options.getWaitPolicy().getProto())
346+
.setLifecycleStage(options.getWaitForStage().getProto())
346347
.build()));
347348

348349
if (result.hasResult()) {
@@ -360,7 +361,7 @@ public <R> UpdateHandle<R> startUpdate(UpdateOptions<R> options, Object... args)
360361
result.getReference().getWorkflowExecution(),
361362
options.getResultClass(),
362363
options.getResultType());
363-
if (options.getWaitPolicy() == WorkflowUpdateStage.COMPLETED) {
364+
if (options.getWaitForStage() == WorkflowUpdateStage.COMPLETED) {
364365
// Don't return the handle until completed, since that's what's been asked for
365366
handle.waitCompleted();
366367
}

temporal-sdk/src/test/java/io/temporal/client/functional/UpdateTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ public void updateNonExistentWorkflowUntyped() {
7070

7171
assertThrows(
7272
WorkflowNotFoundException.class,
73-
() -> workflowStub.startUpdate("update", Void.class, "some-value"));
73+
() ->
74+
workflowStub.startUpdate(
75+
"update", WorkflowUpdateStage.ACCEPTED, Void.class, "some-value"));
7476
}
7577

7678
@Test
@@ -103,7 +105,9 @@ public void updateCompletedWorkflowUntyped() {
103105

104106
assertThrows(
105107
WorkflowNotFoundException.class,
106-
() -> workflowStub.startUpdate("update", Void.class, "some-value"));
108+
() ->
109+
workflowStub.startUpdate(
110+
"update", WorkflowUpdateStage.ACCEPTED, Void.class, "some-value"));
107111
}
108112

109113
@Test
@@ -131,6 +135,7 @@ public void updateWorkflowDuplicateId() throws ExecutionException, InterruptedEx
131135
.setUpdateName("update")
132136
.setUpdateId(updateId)
133137
.setFirstExecutionRunId(execution.getRunId())
138+
.setWaitForStage(WorkflowUpdateStage.ACCEPTED)
134139
.build(),
135140
0,
136141
"some-value")
@@ -146,6 +151,7 @@ public void updateWorkflowDuplicateId() throws ExecutionException, InterruptedEx
146151
.setUpdateName("update")
147152
.setUpdateId(updateId)
148153
.setFirstExecutionRunId(execution.getRunId())
154+
.setWaitForStage(WorkflowUpdateStage.ACCEPTED)
149155
.build(),
150156
"some-other-value")
151157
.getResultAsync()

temporal-sdk/src/test/java/io/temporal/client/functional/UpdateTestTimeout.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.temporal.client.UpdateHandle;
3131
import io.temporal.client.WorkflowClient;
3232
import io.temporal.client.WorkflowStub;
33+
import io.temporal.client.WorkflowUpdateStage;
3334
import io.temporal.testing.internal.SDKTestOptions;
3435
import io.temporal.testing.internal.SDKTestWorkflowRule;
3536
import io.temporal.workflow.*;
@@ -62,7 +63,8 @@ public void closeWorkflowWhileUpdateIsRunning() throws ExecutionException, Inter
6263
SDKTestWorkflowRule.waitForOKQuery(workflowStub);
6364
// Send an update that is accepted, but will not complete.
6465
UpdateHandle<String> handle =
65-
workflowStub.startUpdate("update", String.class, 10_000, "some-value");
66+
workflowStub.startUpdate(
67+
"update", WorkflowUpdateStage.ACCEPTED, String.class, 10_000, "some-value");
6668

6769
// Complete workflow, since the update is accepted it will not block completion
6870
workflowStub.update("complete", void.class);
@@ -81,7 +83,8 @@ public void LongRunningWorkflowUpdateId() throws ExecutionException, Interrupted
8183
workflowStub.start();
8284
SDKTestWorkflowRule.waitForOKQuery(workflowStub);
8385
UpdateHandle<String> handle =
84-
workflowStub.startUpdate("update", String.class, 65_000, "some-value");
86+
workflowStub.startUpdate(
87+
"update", WorkflowUpdateStage.ACCEPTED, String.class, 65_000, "some-value");
8588

8689
assertEquals("some-value", handle.getResultAsync().get());
8790
workflowStub.update("complete", void.class);
@@ -101,7 +104,8 @@ public void WorkflowUpdateGetResultTimeout() throws ExecutionException, Interrup
101104
SDKTestWorkflowRule.waitForOKQuery(workflowStub);
102105

103106
UpdateHandle<String> handle =
104-
workflowStub.startUpdate("update", String.class, 10_000, "some-value");
107+
workflowStub.startUpdate(
108+
"update", WorkflowUpdateStage.ACCEPTED, String.class, 10_000, "some-value");
105109

106110
CompletableFuture<String> result = handle.getResultAsync(2, TimeUnit.SECONDS);
107111
// Verify get throws the correct exception in around the right amount of time

temporal-sdk/src/test/java/io/temporal/workflow/updateTest/UpdateTest.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ public void testUpdateUntyped() throws ExecutionException, InterruptedException
118118
// send an update through the sync path
119119
assertEquals("Execute-Hello", workflowStub.update("update", String.class, 0, "Hello"));
120120
// send an update through the async path
121-
UpdateHandle<String> updateRef = workflowStub.startUpdate("update", String.class, 0, "World");
121+
UpdateHandle<String> updateRef =
122+
workflowStub.startUpdate("update", WorkflowUpdateStage.ACCEPTED, String.class, 0, "World");
122123
assertEquals("Execute-World", updateRef.getResultAsync().get());
123124
// send a bad update that will be rejected through the sync path
124125
assertThrows(
@@ -133,7 +134,9 @@ public void testUpdateUntyped() throws ExecutionException, InterruptedException
133134
// send a bad update that will be rejected through the sync path
134135
assertThrows(
135136
WorkflowUpdateException.class,
136-
() -> workflowStub.startUpdate("update", String.class, 0, "Bad Update"));
137+
() ->
138+
workflowStub.startUpdate(
139+
"update", WorkflowUpdateStage.ACCEPTED, String.class, 0, "Bad Update"));
137140

138141
workflowStub.update("complete", void.class);
139142

@@ -163,7 +166,10 @@ public void testUpdateHandleNotReturnedUntilCompleteWhenAsked()
163166
() -> {
164167
UpdateHandle<String> handle =
165168
workflowStub.startUpdate(
166-
UpdateOptions.newBuilder(String.class).setUpdateName("update").build(),
169+
UpdateOptions.newBuilder(String.class)
170+
.setUpdateName("update")
171+
.setWaitForStage(WorkflowUpdateStage.COMPLETED)
172+
.build(),
167173
"Enchi");
168174
updateCompletedLast.set(true);
169175
try {

temporal-sdk/src/test/java/io/temporal/workflow/updateTest/UpdateTestContinueAsNew.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public void testContinueAsNewInAUpdate() {
8383

8484
// Send an update to continue as new, must be async since the update won't complete
8585
WorkflowStub workflowStub = WorkflowStub.fromTyped(workflow);
86-
workflowStub.startUpdate("update", String.class, 0, "");
86+
workflowStub.startUpdate("update", WorkflowUpdateStage.ACCEPTED, String.class, 0, "");
8787

8888
testWorkflowRule.waitForTheEndOfWFT(execution.getWorkflowId());
8989
testWorkflowRule.invalidateWorkflowCache();

temporal-testing/src/main/java/io/temporal/testing/TimeLockingInterceptor.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121
package io.temporal.testing;
2222

2323
import io.temporal.api.common.v1.WorkflowExecution;
24-
import io.temporal.client.UpdateHandle;
25-
import io.temporal.client.UpdateOptions;
26-
import io.temporal.client.WorkflowOptions;
27-
import io.temporal.client.WorkflowStub;
24+
import io.temporal.client.*;
2825
import io.temporal.common.interceptors.WorkflowClientInterceptorBase;
2926
import io.temporal.serviceclient.TestServiceStubs;
3027
import java.lang.reflect.Type;
@@ -240,8 +237,8 @@ public <R> R update(String updateName, Class<R> resultClass, Object... args) {
240237

241238
@Override
242239
public <R> UpdateHandle<R> startUpdate(
243-
String updateName, Class<R> resultClass, Object... args) {
244-
return next.startUpdate(updateName, resultClass, args);
240+
String updateName, WorkflowUpdateStage waitForStage, Class<R> resultClass, Object... args) {
241+
return next.startUpdate(updateName, waitForStage, resultClass, args);
245242
}
246243

247244
@Override

0 commit comments

Comments
 (0)