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 SagaDefinitionBuilder <FormType> Step() { var sagaStep = new SagaStep(); buildingStep = sagaStep; building.AddStep(sagaStep); return(this); }
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); }
public string KeyOfStep(SagaStep step) { var key = step.Key(); if (key != null) { return(key); } var i = 0; foreach (var s in Steps) { if (s == step) { return(i.ToString()); } i++; } return(step.GetType().FullName); }
public void AddStep(SagaStep step) { _steps.Add(step); }