static ISagaStep getNextStepForElse( ISagaAction sagaAction, ISagaStep step, SagaExecutionState sagaState) { if (step.Is <ISagaStepForElse>()) { bool ifElseResult = getResultFromPrevIfElse( sagaAction.ChildSteps, step, sagaState); // jesli if-else jest spelniony to nie wchodzimy juz do niego // czyli szukamy kolengo kroku poza if-else if (ifElseResult) { ISagaStep nextStepAfterIfElse = GetNextStepAfterIfElse( sagaAction.ChildSteps, step); if (nextStepAfterIfElse != null) { return(nextStepAfterIfElse); } } return(getNextStep(sagaAction, step, sagaState)); } return(step); }
public static ISagaStep GetNextStepToExecute( this ISagaAction sagaAction, ISagaStep step, SagaExecutionState sagaState) { NextStepInfo nextStepForWhile = getNextStepForWhile(sagaAction, step, sagaState); if (nextStepForWhile != null) { return(nextStepForWhile.NextStep); } NextStepInfo nextStepForIf = getNextStepForIf(sagaAction, step, sagaState); if (nextStepForIf != null) { return(nextStepForIf.NextStep); } NextStepInfo nextChildStep = getChildNextStep(step); if (nextChildStep != null) { return(nextChildStep.NextStep); } return(getNextStep(sagaAction, step, sagaState)); }
static NextStepInfo getNextStepForIf( ISagaAction sagaAction, ISagaStep step, SagaExecutionState sagaState) { if (step.Is <ISagaStepForIf>()) { IStepData currentStepData = sagaState.History. GetLatestByStepName(step.StepName); if (currentStepData?.ExecutionData?.ConditionResult == true) { return(new NextStepInfo { NextStep = step.ChildSteps.GetFirstStep() }); } else { return(new NextStepInfo { NextStep = GetNextStepElsewhere(sagaAction.ChildSteps, step) }); } } return(null); }
private string CalculateNextStepName( ISaga saga, ISagaStep sagaStep, ISagaAction sagaAction, StepData stepData, Exception executionError) { if (saga.ExecutionState.IsBreaked) { return(null); } if (executionError != null) { saga.ExecutionState.IsResuming = false; saga.ExecutionState.IsCompensating = true; saga.ExecutionState.CurrentError = executionError.ToSagaStepException(); return(CalculateNextCompensationStep(saga)); } else { string nextStepName = CalculateNextStep(saga, sagaAction, sagaStep, stepData); saga.ExecutionState.IsResuming = false; return(nextStepName); } }
static ISagaStep getNextStep( ISagaAction sagaAction, ISagaStep step, SagaExecutionState sagaState) { ISagaStep nextStepForWhile = getNextStepForWhile(sagaAction, step); if (nextStepForWhile != null) { return(nextStepForWhile); } // szukamy kolejnego kroku ISagaStep nextStep = GetNextStepElsewhere( sagaAction.ChildSteps, step); // sprawdzenie czy rodzic to ELSE nextStep = getNextStepForElse( sagaAction, nextStep, sagaState); return(nextStep); }
public async Task <ISaga> Handle(ExecuteStepCommand command) { ISaga saga = command.Saga; ISagaStep step = command.SagaStep; ISagaAction sagaAction = command.SagaAction; ISagaModel model = command.Model; StepData stepData = GetOrCreateStepData(saga, step, model); MiddlewaresChain middlewaresChain = Middlewares.BuildFullChain( serviceProvider, SaveSaga, ExecuteStep); Exception executionError = null; try { await Middlewares.ExecuteChain( middlewaresChain, saga, step, stepData); stepData. SetSucceeded(saga.ExecutionState, dateTimeProvider); } catch (SagaStopException) { throw; return(null); } catch (Exception ex) { logger. LogError(ex, $"Saga: {saga.Data.ID}; Executing {(step.Async ? "async " : "")}step: {step.StepName}"); executionError = ex; stepData. SetFailed(saga.ExecutionState, dateTimeProvider, executionError.ToSagaStepException()); } finally { middlewaresChain. Clean(); stepData. SetEnded(saga.ExecutionState, dateTimeProvider); } string nextStepName = CalculateNextStepName( saga, step, sagaAction, stepData, executionError); SaveNextStep(saga, stepData, nextStepName); CheckIfSagaIsDeleted(saga); await sagaPersistance.Set(saga); return(saga); }
private async Task ProcessAsync <TMessage>(TMessage message, ISagaAction <TMessage> action, Func <TMessage, ISagaContext, Task> onCompleted, Func <TMessage, ISagaContext, Task> onRejected, ISagaContext context = null) where TMessage : class { context = context ?? SagaContext.Empty; var saga = (ISaga)action; var sagaType = saga.GetType(); var id = saga.ResolveId(message, context); var dataType = saga.GetSagaDataType(); await Semaphore.WaitAsync(); try { var state = await _repository.ReadAsync(id, sagaType).ConfigureAwait(false); if (state is null) { if (!(action is ISagaStartAction <TMessage>)) { return; } state = CreateSagaState(id, sagaType, dataType); } else if (state.State == SagaStates.Rejected) { return; } InitializeSaga(saga, id, state); try { await action.HandleAsync(message, context); } catch (Exception e) { context.SagaContextError = new SagaContextError(e); saga.Reject(); } await UpdateSagaAsync(message, saga, state); } finally { Semaphore.Release(); } if (saga.State is SagaStates.Rejected) { await onRejected(message, context); await CompensateAsync(saga, sagaType, context); } else if (saga.State is SagaStates.Completed) { await onCompleted(message, context); } }
public static ISagaAction FindActionForStateAndEvent( this ISagaModel model, string state, Type eventType) { ISagaAction action = model.FindActionByStateAndEventType(state, eventType); if (action == null) { throw new Exception($"Could not find action for state {state} and event of type {eventType?.Name}"); } return(action); }
static ISagaStep getNextStepForWhile( ISagaAction sagaAction, ISagaStep step) { ISagaStep nextStep = GetNextStepSameLevel( sagaAction.ChildSteps, step); if (nextStep == null && step.ParentStep.Is <ISagaStepForWhile>()) { return(step.ParentStep); } return(null); }
private string CalculateNextStep(ISaga saga, ISagaAction sagaAction, ISagaStep sagaStep, IStepData stepData = null) { if (saga.ExecutionState.IsResuming) { return(sagaStep.StepName); } if (saga.ExecutionState.IsCompensating) { return(CalculateNextCompensationStep(saga)); } return(sagaAction. GetNextStepToExecute(sagaStep, saga.ExecutionState)?.StepName); }
public async Task <ISaga> Handle(ExecuteActionCommand command) { ISaga saga = command.Saga; if (saga == null) { throw new SagaInstanceNotFoundException(command.Model.SagaStateType); } ISagaStep step = command.Model.Actions. FindStepForExecutionStateAndEvent(saga); ISagaAction action = command.Model. FindActionForStep(step); if (step.Async) { saga.ExecutionState.AsyncExecution = AsyncExecution.True(); } ExecuteStepCommand executeStepCommand = new ExecuteStepCommand { Saga = saga, SagaStep = step, SagaAction = action, Model = command.Model }; logger. LogDebug($"Saga: {saga.Data.ID}; Executing {(step.Async ? "async " : "")}step: {step.StepName}"); if (step.Async) { DispatchStepAsync(executeStepCommand); return(saga); } else { using (IServiceScope scope = serviceScopeFactory.CreateScope()) { return(await DispatchStepSync(scope.ServiceProvider, executeStepCommand)); } } }
public static ISagaStep GetStep(this ISagaAction sagaAction, string stepName) { ISagaStep step = sagaAction.ChildSteps.FirstOrDefault(s => s.StepName == stepName); if (step != null) { return(step); } foreach (var childStep in sagaAction.ChildSteps) { step = FindChildStep(childStep, stepName); if (step != null) { return(step); } } return(null); }
private async Task ProcessAsync <TMessage>(TMessage message, ISagaAction <TMessage> action, Func <TMessage, ISagaContext, Task> onCompleted, Func <TMessage, ISagaContext, Task> onRejected, ISagaContext context = null) where TMessage : class { context ??= SagaContext.Empty; var saga = (ISaga)action; var id = saga.ResolveId(message, context); using (await Locker.LockAsync(id)) { var(isInitialized, state) = await _initializer.TryInitializeAsync(saga, id, message); if (!isInitialized) { return; } await _processor.ProcessAsync(saga, message, state, context); await _postProcessor.ProcessAsync(saga, message, context, onCompleted, onRejected); } }
static ISagaStep FindStepForEventType( ISaga saga, Type eventType, ISagaActions actions) { ISagaAction action = actions. FindActionByEventType(eventType); if (action == null) { throw new SagaInvalidEventForStateException(saga.Data.ID, saga.ExecutionState.GetExecutionState(), eventType); } ISagaStep step = action. ChildSteps.GetFirstStep(); if (step == null) { throw new SagaStepNotRegisteredException(saga.Data.ID, saga.ExecutionState.GetExecutionState(), saga.ExecutionState.CurrentStep); } return(step); }
static ISagaStep FindStepForCurrentState( ISaga saga, ISagaActions actions) { ISagaAction action = actions. FindActionByStep(saga.ExecutionState.CurrentStep); if (action == null) { throw new SagaStepNotRegisteredException(saga.Data.ID, saga.ExecutionState.GetExecutionState(), saga.ExecutionState.CurrentStep); } ISagaStep step = action. GetStep(saga.ExecutionState.CurrentStep); if (step == null) { throw new SagaStepNotRegisteredException(saga.Data.ID, saga.ExecutionState.GetExecutionState(), saga.ExecutionState.CurrentStep); } return(step); }
public void Add(ISagaAction action) { actions.Add(action); Rebuild(); }
private async Task ProcessAsync <TMessage>(Guid?nid, Type sagaType, Type sagaDataType, TMessage message, ISagaAction <TMessage> action, ISagaContext context = null) where TMessage : class { context = context ?? SagaContext.Empty; var saga = (ISaga)action; var id = nid ?? saga.ResolveId(message, context); var sagaData = await _repository.ReadAsync(id, sagaType).ConfigureAwait(false); if (sagaData is null) { if (!(action is ISagaStartAction <TMessage>)) { return; } sagaData = SagaData.Create(id, sagaType, SagaStates.Pending, Activator.CreateInstance(sagaDataType)); } else if (sagaData.State == SagaStates.Rejected) { return; } saga.Initialize(sagaData.SagaId, sagaData.State, sagaData.Data); var isError = false; try { await action.HandleAsync(message, context); } catch { isError = true; } var newSagaData = SagaData.Create(id, sagaType, saga.State, saga.Data); var sagaLogData = SagaLogData.Create(id, sagaType, message); var persistanceTasks = new Task[2] { _repository.WriteAsync(newSagaData), _sagaLog.SaveAsync(sagaLogData) }; await Task.WhenAll(persistanceTasks).ConfigureAwait(false); if (saga.State is SagaStates.Rejected || isError) { await CompensateAsync(saga, sagaType, context); } }