@@ -229,6 +229,17 @@ func (r *WorkflowStateReplicatorImpl) ReplicateVersionedTransition(
229
229
default :
230
230
return serviceerror .NewInvalidArgument (fmt .Sprintf ("unknown artifact type %T" , artifactType ))
231
231
}
232
+
233
+ if mutation != nil && mutation .ExclusiveStartVersionedTransition .TransitionCount == 0 {
234
+ // this is the first replication task for this workflow
235
+ // TODO: Handle reset case to reduce the amount of history events write
236
+ err := r .handleFirstReplicationTask (ctx , versionedTransition , sourceClusterName )
237
+ if ! errors .Is (err , consts .ErrDuplicate ) {
238
+ // if ErrDuplicate is returned from creation, it means the workflow is already existed, continue to apply mutation
239
+ return err
240
+ }
241
+ }
242
+
232
243
executionState , executionInfo := func () (* persistencespb.WorkflowExecutionState , * persistencespb.WorkflowExecutionInfo ) {
233
244
if snapshot != nil {
234
245
return snapshot .State .ExecutionState , snapshot .State .ExecutionInfo
@@ -337,6 +348,168 @@ func (r *WorkflowStateReplicatorImpl) ReplicateVersionedTransition(
337
348
}
338
349
}
339
350
351
+ //nolint:revive // cognitive complexity 35 (> max enabled 25)
352
+ func (r * WorkflowStateReplicatorImpl ) handleFirstReplicationTask (
353
+ ctx context.Context ,
354
+ versionedTransitionArtifact * replicationspb.VersionedTransitionArtifact ,
355
+ sourceClusterName string ,
356
+ ) (retErr error ) {
357
+ mutation := versionedTransitionArtifact .GetSyncWorkflowStateMutationAttributes ()
358
+ executionInfo := mutation .StateMutation .ExecutionInfo
359
+ executionState := mutation .StateMutation .ExecutionState
360
+ sourceVersionHistories := mutation .StateMutation .ExecutionInfo .VersionHistories
361
+ currentVersionHistory , err := versionhistory .GetCurrentVersionHistory (sourceVersionHistories )
362
+ if err != nil {
363
+ return err
364
+ }
365
+ lastVersionHistoryItem , err := versionhistory .GetLastVersionHistoryItem (currentVersionHistory )
366
+ if err != nil {
367
+ return err
368
+ }
369
+
370
+ var historyEventBatchs [][]* historypb.HistoryEvent
371
+ for _ , blob := range versionedTransitionArtifact .EventBatches {
372
+ e , err := r .historySerializer .DeserializeEvents (blob )
373
+ if err != nil {
374
+ return err
375
+ }
376
+ historyEventBatchs = append (historyEventBatchs , e )
377
+ }
378
+ lastBatch := historyEventBatchs [len (historyEventBatchs )- 1 ]
379
+ lastEvent := lastBatch [len (lastBatch )- 1 ]
380
+ if lastEvent .EventId < lastVersionHistoryItem .EventId {
381
+ remoteHistoryIterator := collection .NewPagingIterator (r .getHistoryFromRemotePaginationFn (
382
+ ctx ,
383
+ sourceClusterName ,
384
+ namespace .ID (executionInfo .NamespaceId ),
385
+ executionInfo .WorkflowId ,
386
+ executionState .RunId ,
387
+ lastEvent .EventId ,
388
+ lastEvent .Version ,
389
+ lastVersionHistoryItem .EventId + 1 ,
390
+ lastVersionHistoryItem .Version ),
391
+ )
392
+ for remoteHistoryIterator .HasNext () {
393
+ batch , err := remoteHistoryIterator .Next ()
394
+ if err != nil {
395
+ return err
396
+ }
397
+ sourceEvents , err := r .historySerializer .DeserializeEvents (batch .rawHistory )
398
+ if err != nil {
399
+ return err
400
+ }
401
+ historyEventBatchs = append (historyEventBatchs , sourceEvents )
402
+ }
403
+ }
404
+
405
+ wfCtx , releaseFn , err := r .workflowCache .GetOrCreateWorkflowExecution (
406
+ ctx ,
407
+ r .shardContext ,
408
+ namespace .ID (executionInfo .NamespaceId ),
409
+ & commonpb.WorkflowExecution {
410
+ WorkflowId : executionInfo .WorkflowId ,
411
+ RunId : executionState .RunId ,
412
+ },
413
+ locks .PriorityLow ,
414
+ )
415
+ if err != nil {
416
+ return err
417
+ }
418
+ defer func () {
419
+ if rec := recover (); rec != nil {
420
+ releaseFn (errPanic )
421
+ panic (rec )
422
+ }
423
+ releaseFn (retErr )
424
+ }()
425
+
426
+ nsEntry , err := r .namespaceRegistry .GetNamespaceByID (namespace .ID (executionInfo .NamespaceId ))
427
+ if err != nil {
428
+ return err
429
+ }
430
+ localMutableState := workflow .NewMutableState (
431
+ r .shardContext ,
432
+ r .shardContext .GetEventsCache (),
433
+ r .logger ,
434
+ nsEntry ,
435
+ executionInfo .WorkflowId ,
436
+ executionState .RunId ,
437
+ timestamp .TimeValue (executionState .StartTime ),
438
+ )
439
+ err = localMutableState .ApplyMutation (mutation .StateMutation )
440
+ if err != nil {
441
+ return err
442
+ }
443
+
444
+ err = localMutableState .SetHistoryTree (executionInfo .WorkflowExecutionTimeout , executionInfo .WorkflowRunTimeout , executionState .RunId )
445
+ if err != nil {
446
+ return nil
447
+ }
448
+ localCurrentVersionHistory , err := versionhistory .GetCurrentVersionHistory (localMutableState .GetExecutionInfo ().VersionHistories )
449
+ if err != nil {
450
+ return err
451
+ }
452
+ defer func () {
453
+ if retErr != nil {
454
+ // if we fail to create workflow, we need to clean up the history branch
455
+ if err := r .shardContext .GetExecutionManager ().DeleteHistoryBranch (ctx , & persistence.DeleteHistoryBranchRequest {
456
+ ShardID : r .shardContext .GetShardID (),
457
+ BranchToken : localCurrentVersionHistory .BranchToken ,
458
+ }); err != nil {
459
+ r .logger .Error ("failed to clean up workflow execution" , tag .Error (err ))
460
+ }
461
+ }
462
+ }()
463
+ if err != nil {
464
+ return err
465
+ }
466
+
467
+ localCurrentVersionHistory .Items = versionhistory .CopyVersionHistoryItems (currentVersionHistory .Items )
468
+ if err != nil {
469
+ return err
470
+ }
471
+
472
+ localMutableState .SetHistoryBuilder (historybuilder .NewImmutable (historyEventBatchs ... ))
473
+ for _ , historyEventBatch := range historyEventBatchs {
474
+ for _ , historyEvent := range historyEventBatch {
475
+ r .addEventToCache (definition.WorkflowKey {
476
+ NamespaceID : executionInfo .NamespaceId ,
477
+ WorkflowID : executionInfo .WorkflowId ,
478
+ RunID : executionState .RunId ,
479
+ }, historyEvent )
480
+ }
481
+ }
482
+ if versionedTransitionArtifact .NewRunInfo != nil {
483
+ err = r .createNewRunWorkflow (
484
+ ctx ,
485
+ namespace .ID (executionInfo .NamespaceId ),
486
+ executionInfo .WorkflowId ,
487
+ versionedTransitionArtifact .NewRunInfo ,
488
+ localMutableState ,
489
+ true ,
490
+ )
491
+ if err != nil {
492
+ return err
493
+ }
494
+ }
495
+
496
+ err = r .taskRefresher .Refresh (ctx , localMutableState )
497
+
498
+ if err != nil {
499
+ return err
500
+ }
501
+
502
+ return r .transactionMgr .CreateWorkflow (
503
+ ctx ,
504
+ NewWorkflow (
505
+ r .clusterMetadata ,
506
+ wfCtx ,
507
+ localMutableState ,
508
+ releaseFn ,
509
+ ),
510
+ )
511
+ }
512
+
340
513
func (r * WorkflowStateReplicatorImpl ) applyMutation (
341
514
ctx context.Context ,
342
515
namespaceID namespace.ID ,
@@ -370,7 +543,8 @@ func (r *WorkflowStateReplicatorImpl) applyMutation(
370
543
if workflow .TransitionHistoryStalenessCheck (localTransitionHistory , mutation .ExclusiveStartVersionedTransition ) != nil ||
371
544
workflow .TransitionHistoryStalenessCheck (sourceTransitionHistory , localVersionedTransition ) != nil {
372
545
return serviceerrors .NewSyncState (
373
- fmt .Sprintf ("Failed to apply mutation due to version check failed. local transition history: %v, source transition history: %v" , localTransitionHistory , sourceTransitionHistory ),
546
+ fmt .Sprintf ("Failed to apply mutation due to version check failed. local transition history: %v, source transition history: %v, exclusiveStartVersionedTransition: %v" ,
547
+ localTransitionHistory , sourceTransitionHistory , mutation .ExclusiveStartVersionedTransition ),
374
548
namespaceID .String (),
375
549
workflowID ,
376
550
runID ,
0 commit comments