in common/persistence/operationModeValidator.go [170:328]
func ValidateConflictResolveWorkflowModeState(
mode ConflictResolveWorkflowMode,
resetWorkflowSnapshot InternalWorkflowSnapshot,
newWorkflowSnapshot *InternalWorkflowSnapshot,
currentWorkflowMutation *InternalWorkflowMutation,
) error {
resetWorkflowState := resetWorkflowSnapshot.ExecutionInfo.State
if err := checkWorkflowState(resetWorkflowState); err != nil {
return err
}
var newWorkflowState *int
if newWorkflowSnapshot != nil {
newWorkflowState = &newWorkflowSnapshot.ExecutionInfo.State
if err := checkWorkflowState(*newWorkflowState); err != nil {
return err
}
}
var currentWorkflowState *int
if currentWorkflowMutation != nil {
currentWorkflowState = ¤tWorkflowMutation.ExecutionInfo.State
if err := checkWorkflowState(*currentWorkflowState); err != nil {
return err
}
}
switch mode {
case ConflictResolveWorkflowModeUpdateCurrent:
// update current record
// 1. reset workflow only ->
// reset workflow cannot be zombie
// 2. reset workflow & new workflow ->
// reset workflow cannot be created / running / zombie,
// new workflow cannot be zombie / completed
// 3. current workflow & reset workflow ->
// current workflow cannot be created / running,
// reset workflow cannot be zombie
// 4. current workflow & reset workflow & new workflow ->
// current workflow cannot be created / running,
// reset workflow cannot be created / running / zombie,
// new workflow cannot be zombie / completed
// TODO remove case 1 & 2 support once 2DC is deprecated
// it is ok that currentWorkflowMutation is null, only for 2 DC case
// NDC should always require current workflow for CAS
// Note: current workflow mutation can be in zombie state, for the update
// case 1 & 2
if currentWorkflowState == nil {
// case 1
if newWorkflowState == nil {
if resetWorkflowState == WorkflowStateZombie {
return newInvalidConflictResolveWorkflowMode(
mode,
resetWorkflowState,
)
}
return nil
}
// case 2
if resetWorkflowState == WorkflowStateCreated ||
resetWorkflowState == WorkflowStateRunning ||
resetWorkflowState == WorkflowStateZombie ||
*newWorkflowState == WorkflowStateZombie ||
*newWorkflowState == WorkflowStateCompleted {
return newInvalidConflictResolveWorkflowWithNewMode(
mode,
resetWorkflowState,
*newWorkflowState,
)
}
return nil
}
// case 3 & 4
// case 3
if newWorkflowState == nil {
if *currentWorkflowState == WorkflowStateCreated ||
*currentWorkflowState == WorkflowStateRunning ||
resetWorkflowState == WorkflowStateZombie {
return newInvalidConflictResolveWorkflowWithCurrentMode(
mode,
resetWorkflowState,
*currentWorkflowState,
)
}
return nil
}
// case 4
if *currentWorkflowState == WorkflowStateCreated ||
*currentWorkflowState == WorkflowStateRunning ||
resetWorkflowState == WorkflowStateCreated ||
resetWorkflowState == WorkflowStateRunning ||
resetWorkflowState == WorkflowStateZombie ||
*newWorkflowState == WorkflowStateZombie ||
*newWorkflowState == WorkflowStateCompleted {
return newInvalidConflictResolveWorkflowWithCurrentWithNewMode(
mode,
resetWorkflowState,
*newWorkflowState,
*currentWorkflowState,
)
}
return nil
case ConflictResolveWorkflowModeBypassCurrent:
// bypass current record
// * current workflow cannot be set
// 1. reset workflow only ->
// reset workflow cannot be created / running
// 2. reset workflow & new workflow ->
// reset workflow cannot be created / running / zombie,
// new workflow cannot be created / running / completed
// precondition
if currentWorkflowMutation != nil {
return &types.InternalServiceError{
Message: fmt.Sprintf(
"Invalid workflow conflict resolve mode %v, encounter current workflow",
mode,
),
}
}
// case 1
if newWorkflowState == nil {
if resetWorkflowState == WorkflowStateCreated ||
resetWorkflowState == WorkflowStateRunning {
return newInvalidConflictResolveWorkflowMode(
mode,
resetWorkflowState,
)
}
return nil
}
// case 2
if resetWorkflowState == WorkflowStateCreated ||
resetWorkflowState == WorkflowStateRunning ||
resetWorkflowState == WorkflowStateZombie ||
*newWorkflowState == WorkflowStateCreated ||
*newWorkflowState == WorkflowStateRunning ||
*newWorkflowState == WorkflowStateCompleted {
return newInvalidConflictResolveWorkflowWithNewMode(
mode,
resetWorkflowState,
*newWorkflowState,
)
}
return nil
default:
return &types.InternalServiceError{
Message: fmt.Sprintf("unknown mode: %v", mode),
}
}
}