Skip to content

Commit ab81e28

Browse files
Fix race
1 parent b3c096d commit ab81e28

1 file changed

Lines changed: 16 additions & 11 deletions

File tree

temporal-sdk/src/main/java/io/temporal/nexus/TemporalNexusClientImpl.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.temporal.internal.nexus.NexusStartWorkflowHelper;
1212
import io.temporal.workflow.Functions;
1313
import java.util.Objects;
14+
import java.util.concurrent.atomic.AtomicBoolean;
1415

1516
/** Package-private implementation of {@link TemporalNexusClient}. */
1617
@Experimental
@@ -19,7 +20,7 @@ final class TemporalNexusClientImpl implements TemporalNexusClient {
1920
private final WorkflowClient client;
2021
private final OperationContext operationContext;
2122
private final OperationStartDetails operationStartDetails;
22-
private boolean asyncOperationStarted;
23+
private final AtomicBoolean asyncOperationStarted = new AtomicBoolean(false);
2324

2425
TemporalNexusClientImpl(
2526
WorkflowClient client,
@@ -198,21 +199,25 @@ public <R> TemporalOperationResult<R> startWorkflow(
198199
}
199200

200201
private <R> TemporalOperationResult<R> invokeAndReturn(WorkflowHandle<R> handle) {
201-
if (asyncOperationStarted) {
202+
if (!asyncOperationStarted.compareAndSet(false, true)) {
202203
throw new HandlerException(
203204
HandlerException.ErrorType.BAD_REQUEST,
204205
new IllegalStateException(
205206
"Only one async operation can be started per operation handler invocation. "
206207
+ "Use getWorkflowClient() for additional workflow interactions."));
207208
}
208-
NexusStartWorkflowResponse response =
209-
NexusStartWorkflowHelper.startWorkflowAndAttachLinks(
210-
operationContext,
211-
operationStartDetails,
212-
request -> handle.getInvoker().invoke(request));
213-
// Set after successful start so that if startWorkflowAndAttachLinks throws,
214-
// the handler can retry without being blocked by the guard.
215-
asyncOperationStarted = true;
216-
return TemporalOperationResult.async(response.getOperationToken());
209+
try {
210+
NexusStartWorkflowResponse response =
211+
NexusStartWorkflowHelper.startWorkflowAndAttachLinks(
212+
operationContext,
213+
operationStartDetails,
214+
request -> handle.getInvoker().invoke(request));
215+
return TemporalOperationResult.async(response.getOperationToken());
216+
} catch (Throwable t) {
217+
// Reset on failure so that if startWorkflowAndAttachLinks throws,
218+
// the handler can retry without being blocked by the guard.
219+
asyncOperationStarted.set(false);
220+
throw t;
221+
}
217222
}
218223
}

0 commit comments

Comments
 (0)