1111import io .temporal .internal .nexus .NexusStartWorkflowHelper ;
1212import io .temporal .workflow .Functions ;
1313import 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