Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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));
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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);
            }
        }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        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));
                }
            }
        }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
        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);
            }
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
        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);
        }
Ejemplo n.º 16
0
 public void Add(ISagaAction action)
 {
     actions.Add(action);
     Rebuild();
 }
Ejemplo n.º 17
0
        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);
            }
        }