예제 #1
0
        protected string makeSagaIdAndStepKey <FormType>(string sagaId,
                                                         SimpleSaga <FormType> saga, SagaStep step) where FormType : class, SagaData
        {
            var stepKey = saga.GetSagaDefinition().KeyOfStep(step);

            return($"{sagaId}-{stepKey}");
        }
예제 #2
0
        public async Task CompensationDone <FormType>(SimpleSaga <FormType> saga,
                                                      SagaStep step, string sagaId, SagaData form) where FormType : class, SagaData
        {
            var stepKey = saga.GetSagaDefinition().KeyOfStep(step);

            sagaDoneCompensationSteps.AddOrUpdate(sagaId, new HashSet <string>()
            {
                stepKey
            }, (_, oldSet) => {
                oldSet.Add(stepKey);
                return(oldSet);
            });
            var doneCompensationSteps        = sagaDoneCompensationSteps[sagaId];
            var needDoCompensationStepsCount = saga.GetSagaDefinition().Steps.Count(); // 此sagaId需要执行补偿的steps count

            if (doneCompensationSteps.Count() >= needDoCompensationStepsCount)
            {
                // sagaStates[sagaId] = SagaState.COMPENSATION_DONE;
                var oldInfo = _sagaInfos[sagaId];
                if (oldInfo.State != SagaState.COMPENSATION_DONE)
                {
                    if (!_sagaInfos.TryUpdate(sagaId, oldInfo.SetStateClone(SagaState.COMPENSATION_DONE), oldInfo))
                    {
                        throw new SagaAbortException($"saga {sagaId} CompensationDone error because of state update conflict");
                    }
                }
                saga.OnSagaRolledBack(sagaId, form);
            }
            return;
        }
예제 #3
0
        public async Task <string> CreateSagaId <FormType>(SimpleSaga <FormType> saga) where FormType : class, SagaData
        {
            var sagaId = Guid.NewGuid().ToString();
            //sagaIdsStartTimes[sagaId] = DateTime.UtcNow;
            //sagaStates[sagaId] = SagaState.PROCESSING;
            var now        = DateTime.UtcNow;
            var definition = saga.GetSagaDefinition();

            try
            {
                var sagaInfo = new SagaInfo
                {
                    SagaId          = sagaId,
                    State           = SagaState.PROCESSING,
                    FailTimes       = 0,
                    SagaCreateTime  = now,
                    LastProcessTime = now,
                    Definition      = definition
                };
                _sagaInfos[sagaId] = sagaInfo;
            } catch (Exception e)
            {
                Console.WriteLine($"erro {e.Message}");
            }
            return(sagaId);
        }
예제 #4
0
 public async Task CompensationStart <FormType>(SimpleSaga <FormType> saga,
                                                string sagaId, SagaData form) where FormType : class, SagaData
 {
     if (!await SetSagaState(sagaId, SagaState.COMPENSATION_DOING, null))
     {
         throw new SagaAbortException($"sagaId {sagaId} CompensationStart error because of set state conflict");
     }
 }
예제 #5
0
        protected int SINGLE_STEP_COMPENSATION_TRY_COUNT = 3; // 一个步骤的补偿任务最多重试的次数

        public Task CompensationException <FormType>(SimpleSaga <FormType> saga,
                                                     SagaStep step, string sagaId, SagaData form, Exception e) where FormType : class, SagaData
        {
            // 记录失败信息和失败次数
            var key = makeSagaIdAndStepKey(sagaId, saga, step);

            sagaStepsCompensationFailCount.AddOrUpdate(key, 1, (_, oldCount) => oldCount + 1);
            var failCount = sagaStepsCompensationFailCount[key];

            if (failCount >= SINGLE_STEP_COMPENSATION_TRY_COUNT)
            {
                // 这个step的补偿任务执行失败次数太多了
                Console.WriteLine($"saga {sagaId} step {saga.GetSagaDefinition().KeyOfStep(step)} compensation fail too many times error {e.Message}");
                // sagaStates.TryUpdate(sagaId, SagaState.COMPENSATION_FAIL, SagaState.COMPENSATION_DOING);
                while (true)
                {
                    if (!_sagaInfos.ContainsKey(sagaId))
                    {
                        break;
                    }
                    var oldInfo = _sagaInfos[sagaId];
                    if (oldInfo.State.IsEndState())
                    {
                        break;
                    }
                    if (_sagaInfos.TryUpdate(sagaId, oldInfo.SetStateClone(SagaState.COMPENSATION_FAIL), oldInfo))
                    {
                        break;
                    }
                }
            }
            else
            {
                while (true)
                {
                    if (!_sagaInfos.ContainsKey(sagaId))
                    {
                        break;
                    }
                    var oldInfo = _sagaInfos[sagaId];
                    if (oldInfo.State.IsEndState() || oldInfo.State == SagaState.COMPENSATION_ERROR)
                    {
                        break;
                    }
                    if (_sagaInfos.TryUpdate(sagaId, oldInfo.SetStateClone(SagaState.COMPENSATION_ERROR), oldInfo))
                    {
                        break;
                    }
                }
            }
            return(Task.CompletedTask);
        }