@@ -253,64 +253,83 @@ StartWorkflowExecutionResponse startWorkflowExecutionImpl(
253
253
WorkflowId workflowId = new WorkflowId (namespace , requestWorkflowId );
254
254
WorkflowIdReusePolicy reusePolicy = startRequest .getWorkflowIdReusePolicy ();
255
255
WorkflowIdConflictPolicy conflictPolicy = startRequest .getWorkflowIdConflictPolicy ();
256
- if (conflictPolicy != WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_UNSPECIFIED
257
- && reusePolicy == WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING ) {
258
- throw createInvalidArgument (
259
- "Invalid WorkflowIDReusePolicy: WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING cannot be used together with a WorkflowIDConflictPolicy." );
260
- }
261
256
257
+ validateWorkflowIdReusePolicy (reusePolicy , conflictPolicy );
262
258
validateOnConflictOptions (startRequest );
263
259
260
+ // Backwards compatibility: WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING is deprecated
261
+ if (reusePolicy == WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING ) {
262
+ conflictPolicy = WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING ;
263
+ reusePolicy = WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE ;
264
+ }
265
+ if (conflictPolicy == WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_UNSPECIFIED ) {
266
+ conflictPolicy = WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_FAIL ;
267
+ }
268
+ if (reusePolicy == WORKFLOW_ID_REUSE_POLICY_UNSPECIFIED ) {
269
+ reusePolicy = WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE ;
270
+ }
271
+
264
272
TestWorkflowMutableState existing ;
265
273
lock .lock ();
266
274
try {
267
275
String newRunId = UUID .randomUUID ().toString ();
268
276
existing = executionsByWorkflowId .get (workflowId );
269
277
if (existing != null ) {
270
- WorkflowExecutionStatus status = existing .getWorkflowExecutionStatus ();
278
+ StartWorkflowExecutionResponse dedupedResponse = dedupeRequest (startRequest , existing );
279
+ if (dedupedResponse != null ) {
280
+ return dedupedResponse ;
281
+ }
271
282
283
+ WorkflowExecutionStatus status = existing .getWorkflowExecutionStatus ();
272
284
if (status == WORKFLOW_EXECUTION_STATUS_RUNNING ) {
273
- StartWorkflowExecutionResponse dedupedResponse = dedupeRequest (startRequest , existing );
274
- if (dedupedResponse != null ) {
275
- return dedupedResponse ;
285
+ switch (conflictPolicy ) {
286
+ case WORKFLOW_ID_CONFLICT_POLICY_FAIL :
287
+ return throwDuplicatedWorkflow (startRequest , existing );
288
+ case WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING :
289
+ if (startRequest .hasOnConflictOptions ()) {
290
+ existing .applyOnConflictOptions (startRequest );
291
+ }
292
+ return StartWorkflowExecutionResponse .newBuilder ()
293
+ .setStarted (false )
294
+ .setRunId (existing .getExecutionId ().getExecution ().getRunId ())
295
+ .build ();
296
+ case WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING :
297
+ existing .terminateWorkflowExecution (
298
+ TerminateWorkflowExecutionRequest .newBuilder ()
299
+ .setNamespace (startRequest .getNamespace ())
300
+ .setWorkflowExecution (existing .getExecutionId ().getExecution ())
301
+ .setReason ("TerminateIfRunning WorkflowIdReusePolicy Policy" )
302
+ .setIdentity ("history-service" )
303
+ .setDetails (
304
+ Payloads .newBuilder ()
305
+ .addPayloads (
306
+ Payload .newBuilder ()
307
+ .setData (
308
+ ByteString .copyFromUtf8 (
309
+ String .format (
310
+ "terminated by new runID: %s" , newRunId )))
311
+ .build ())
312
+ .build ())
313
+ .build ());
314
+ break ;
276
315
}
316
+ }
277
317
278
- if (reusePolicy == WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING
279
- || conflictPolicy
280
- == WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING ) {
281
- existing .terminateWorkflowExecution (
282
- TerminateWorkflowExecutionRequest .newBuilder ()
283
- .setNamespace (startRequest .getNamespace ())
284
- .setWorkflowExecution (existing .getExecutionId ().getExecution ())
285
- .setReason ("TerminateIfRunning WorkflowIdReusePolicy Policy" )
286
- .setIdentity ("history-service" )
287
- .setDetails (
288
- Payloads .newBuilder ()
289
- .addPayloads (
290
- Payload .newBuilder ()
291
- .setData (
292
- ByteString .copyFromUtf8 (
293
- String .format ("terminated by new runID: %s" , newRunId )))
294
- .build ())
295
- .build ())
296
- .build ());
297
- } else if (conflictPolicy
298
- == WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING ) {
299
- if (startRequest .hasOnConflictOptions ()) {
300
- existing .applyOnConflictOptions (startRequest );
318
+ // Status of existing workflow could have changed to TERMINATED.
319
+ status = existing .getWorkflowExecutionStatus ();
320
+
321
+ // At this point, the existing workflow already completed or was terminated.
322
+ switch (reusePolicy ) {
323
+ case WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE :
324
+ break ;
325
+ case WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY :
326
+ if (status == WORKFLOW_EXECUTION_STATUS_COMPLETED
327
+ || status == WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW ) {
328
+ return throwDuplicatedWorkflow (startRequest , existing );
301
329
}
302
- return StartWorkflowExecutionResponse .newBuilder ()
303
- .setStarted (false )
304
- .setRunId (existing .getExecutionId ().getExecution ().getRunId ())
305
- .build ();
306
- } else {
330
+ break ;
331
+ case WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE :
307
332
return throwDuplicatedWorkflow (startRequest , existing );
308
- }
309
- } else if (reusePolicy == WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE
310
- || (reusePolicy == WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY
311
- && (status == WORKFLOW_EXECUTION_STATUS_COMPLETED
312
- || status == WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW ))) {
313
- return throwDuplicatedWorkflow (startRequest , existing );
314
333
}
315
334
}
316
335
@@ -373,14 +392,28 @@ private StartWorkflowExecutionResponse throwDuplicatedWorkflow(
373
392
WorkflowExecutionAlreadyStartedFailure .getDescriptor ());
374
393
}
375
394
395
+ private void validateWorkflowIdReusePolicy (
396
+ WorkflowIdReusePolicy reusePolicy , WorkflowIdConflictPolicy conflictPolicy ) {
397
+ if (conflictPolicy != WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_UNSPECIFIED
398
+ && reusePolicy == WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING ) {
399
+ throw createInvalidArgument (
400
+ "Invalid WorkflowIDReusePolicy: WORKFLOW_ID_REUSE_POLICY_TERMINATE_IF_RUNNING cannot be used together with a WorkflowIDConflictPolicy." );
401
+ }
402
+ if (conflictPolicy == WorkflowIdConflictPolicy .WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING
403
+ && reusePolicy == WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE ) {
404
+ throw createInvalidArgument (
405
+ "Invalid WorkflowIDReusePolicy: WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE cannot be used together with WorkflowIdConflictPolicy WORKFLOW_ID_CONFLICT_POLICY_TERMINATE_EXISTING" );
406
+ }
407
+ }
408
+
376
409
private void validateOnConflictOptions (StartWorkflowExecutionRequest startRequest ) {
377
410
if (!startRequest .hasOnConflictOptions ()) {
378
411
return ;
379
412
}
380
413
OnConflictOptions options = startRequest .getOnConflictOptions ();
381
414
if (options .getAttachCompletionCallbacks () && !options .getAttachRequestId ()) {
382
415
throw createInvalidArgument (
383
- "Invalid OnConflictOptions: AttachCompletionCallbacks cannot be 'true' if AttachRequestId is 'false'." );
416
+ "Invalid OnConflictOptions: AttachCompletionCallbacks cannot be 'true' if AttachRequestId is 'false'." );
384
417
}
385
418
}
386
419
0 commit comments