protected string makeSagaIdAndStepKey <FormType>(string sagaId, SimpleSaga <FormType> saga, SagaStep step) where FormType : class, SagaData { var stepKey = saga.GetSagaDefinition().KeyOfStep(step); return($"{sagaId}-{stepKey}"); }
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; }
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); }
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"); } }
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); }