public async Task Resume(Guid id)
        {
            List <string> invalidModels = new List <string>();

            ISaga saga = await sagaPersistance.Get(id);

            ISagaModel model = sagaRegistrator.FindModelByName(saga.ExecutionInfo.ModelName);

            if (model == null)
            {
                invalidModels.Add(saga.ExecutionInfo.ModelName);
            }

            if (invalidModels.Count > 0)
            {
                throw new Exception($"Saga models {string.Join(", ", invalidModels.Distinct().ToArray())} not found");
            }

            await ExecuteSaga(
                new EmptyEvent(),
                model,
                saga,
                saga.Data.ID,
                null,
                true);
        }
        public async Task <ISaga> Publish(ISagaEvent @event, IDictionary <string, object> executionValues)
        {
            Type   eventType = @event.GetType();
            SagaID sagaId    = SagaID.From(@event.ID);

            ISagaModel model = sagaRegistrator.
                               FindModelForEventType(eventType);

            if (model == null)
            {
                throw new SagaEventNotRegisteredException(eventType);
            }

            ISaga newSaga = await CreateNewSagaIfRequired(model, sagaId, eventType);

            try
            {
                return(await ExecuteSaga(
                           @event,
                           model,
                           newSaga,
                           SagaID.From(newSaga?.Data?.ID ?? sagaId.Value),
                           executionValues,
                           false));
            }
            catch
            {
                //if (newSaga != null)
                //    await sagaPersistance.Remove(newSaga.Data.ID);

                throw;
            }
        }
        private async Task <ISaga> CreateNewSaga(ISagaModel model, SagaID id)
        {
            if (id == SagaID.Empty())
            {
                id = SagaID.New();
            }

            ISagaData data = (ISagaData)Activator.CreateInstance(model.SagaStateType);

            data.ID = id;

            ISaga saga = new Saga
            {
                Data          = data,
                ExecutionInfo = new SagaExecutionInfo
                {
                    ModelName = model.Name,
                    Created   = dateTimeProvider.Now,
                    Modified  = dateTimeProvider.Now
                },
                ExecutionState = new SagaExecutionState
                {
                    CurrentState = new SagaStartState().GetStateName(),
                    CurrentStep  = null
                }
            };

            return(saga);
        }
        public static ISagaAction FindActionForStep(
            this ISagaModel model, ISagaStep sagaStep)

        {
            return(model.Actions.
                   FindActionByStep(sagaStep?.StepName));
        }
        private void RegisterAllModelWithBuilders()
        {
            if (wasInitialized)
            {
                return;
            }

            Type[] modelBuildersTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
                                        .Where(t => t.IsClass && t.Is(typeof(ISagaModelBuilder <>))).ToArray();

            foreach (Type modelBuilderType in modelBuildersTypes)
            {
                object modelBuilder = ActivatorUtilities.CreateInstance(serviceProvider, modelBuilderType);

                ISagaModelBuilder <ISagaData> emptyBuildModel = null;
                string     buildMethodName = nameof(emptyBuildModel.Build);
                MethodInfo?buildMethodInfo =
                    modelBuilderType.GetMethod(buildMethodName, BindingFlags.Public | BindingFlags.Instance);
                ISagaModel model = (ISagaModel)buildMethodInfo.Invoke(modelBuilder, new object[0]);

                Register(model);
            }

            wasInitialized = true;
        }
Пример #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);
        }
Пример #7
0
 public AnnotatedSaga(string sagaId, ISet <AssociationValue> associationValues, T annotatedSaga, ITrackingToken trackingToken, ISagaModel metaModel)
 {
     _sagaInstance     = annotatedSaga;
     _metaModel        = metaModel;
     SagaIdentifier    = sagaId;
     AssociationValues = new AssociationValuesImpl(associationValues);
     _trackingToken    = trackingToken;
 }
Пример #8
0
 public AsyncStepCompletedMessage(SagaID sagaID, string currentState,
                                  string currentStep, bool isCompensating, ISagaModel model)
 {
     SagaID         = sagaID;
     CurrentState   = currentState;
     CurrentStep    = currentStep;
     IsCompensating = isCompensating;
     Model          = model;
 }
Пример #9
0
 public SagaBuilderState(Type currentEvent, string currentState, ISagaModel model,
                         IServiceProvider serviceProvider, UniqueNameGenerator uniqueNameGenerator, ISagaStep parentStep)
 {
     CurrentEvent        = currentEvent;
     CurrentState        = currentState;
     Model               = model;
     ServiceProvider     = serviceProvider;
     UniqueNameGenerator = uniqueNameGenerator;
     ParentStep          = parentStep;
 }
Пример #10
0
        private StepData GetOrCreateStepData(ISaga saga, ISagaStep sagaStep, ISagaModel model)
        {
            saga.ExecutionState.CurrentStep = sagaStep.StepName;
            saga.ExecutionInfo.Modified     = dateTimeProvider.Now;

            StepData stepData = saga.ExecutionState.History.
                                Create(saga, sagaStep, model).
                                SetStarted(saga.ExecutionState, dateTimeProvider);

            return(stepData);
        }
        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);
        }
        private async Task <ISaga> CreateNewSagaIfRequired(ISagaModel model, SagaID id, Type eventType)
        {
            ISaga saga = null;

            if (eventType != null)
            {
                bool isStartEvent = model.Actions.IsStartEvent(eventType);

                if (isStartEvent)
                {
                    saga = await CreateNewSaga(model, id);
                }
            }

            return(saga);
        }
Пример #13
0
        public async Task <ISaga> Publish(ISagaEvent @event, IDictionary <string, object> executionValues, Guid?parentId, SagaRunOptions runOptions)
        {
            runOptions = runOptions ?? new SagaRunOptions();

            Type   eventType = @event.GetType();
            SagaID sagaId    = SagaID.From(@event.ID);

            ISagaModel model = sagaRegistrator.
                               FindModelForEventType(eventType);

            if (model == null)
            {
                throw new SagaEventNotRegisteredException(eventType);
            }

            SagaID?parentSagaId = parentId == null ? (SagaID?)null : SagaID.From(parentId.Value);
            ISaga  newSaga      = await CreateNewSagaIfRequired(model, sagaId, parentSagaId, eventType);

            var id = SagaID.From(newSaga?.Data?.ID ?? sagaId.Value);

            try
            {
                var createdSaga = await ExecuteSaga(
                    @event,
                    model,
                    newSaga,
                    id,
                    executionValues,
                    false,
                    runOptions);

                return(createdSaga);
            }

            /*catch (SagaStopException ex)
             * {
             *   return await sagaPersistance.Get(id.Value);
             * }*/
            catch
            {
                //if (newSaga != null)
                //    await sagaPersistance.Remove(newSaga.Data.ID);

                throw;
            }
        }
        public async Task ResumeAll()
        {
            IList <Guid> ids = await sagaPersistance.GetUnfinished();

            List <string> invalidModels = new List <string>();

            foreach (Guid id in ids)
            {
                ISaga saga = await sagaPersistance.Get(id);

                ISagaModel model = sagaRegistrator.FindModelByName(saga.ExecutionInfo.ModelName);

                if (model == null)
                {
                    invalidModels.Add(saga.ExecutionInfo.ModelName);
                }
            }

            if (invalidModels.Count > 0)
            {
                throw new Exception($"Saga models {string.Join(", ", invalidModels.Distinct().ToArray())} not found");
            }

            foreach (Guid id in ids)
            {
                ISaga saga = await sagaPersistance.Get(id);

                ISagaModel model = sagaRegistrator.FindModelByName(saga.ExecutionInfo.ModelName);

                logger.
                LogInformation($"Trying to resume saga: {id}");

                await ExecuteSaga(
                    new EmptyEvent(),
                    model,
                    saga,
                    saga.Data.ID,
                    null,
                    true);
            }
        }
        public static ISagaAction FindActionByStateAndEventType(
            this ISagaModel model, string stateName, Type eventType)

        {
            return(model.Actions.FindActionByStateAndEventType(stateName, eventType));
        }
Пример #16
0
        public StepData Create(
            ISaga saga,
            ISagaStep step,
            ISagaModel model)
        {
            StepData stepData = saga.ExecutionState.History.
                                GetLastWithStepName(saga.ExecutionState.ExecutionID, saga.ExecutionState.CurrentStep);

            if (!saga.ExecutionState.IsCompensating &&
                stepData != null &&
                stepData.CompensationData == null &&
                stepData.ExecutionData != null &&
                stepData.ResumeData?.EndTime == null)
            {
                if (!saga.ExecutionState.CanBeResumed)
                {
                    saga.ExecutionState.IsCompensating = true;
                    saga.ExecutionState.IsResuming     = false;
                }
                else if (model.ResumePolicy == ESagaResumePolicy.DoFullCompensation)
                {
                    throw new SagaCompensateAllOnResumeException();
                }
                else if (model.ResumePolicy == ESagaResumePolicy.DoCurrentStepCompensation)
                {
                    saga.ExecutionState.IsResuming = true;
                }
                else
                {
                    saga.ExecutionState.IsResuming = false;
                }
            }
            else
            {
                //stepData = null;
            }

            if (saga.ExecutionState.IsResuming)
            {
                stepData.ResumeData = new StepExecutionData
                {
                };
            }
            else if (saga.ExecutionState.IsCompensating)
            {
                stepData = saga.ExecutionState.History.
                           GetLatestCompensationByStepName(
                    saga.ExecutionState.ExecutionID,
                    saga.ExecutionState.CurrentStep);

                stepData.CompensationData = new StepExecutionData()
                {
                };
            }
            else
            {
                if (stepData == null)
                {
                    stepData = new StepData();
                    stepData.ExecutionValues = new StepExecutionValues();
                    stepData.ExecutionID     = saga.ExecutionState.ExecutionID;
                    stepData.AsyncExecution  = saga.ExecutionState.AsyncExecution;
                    stepData.AsyncStep       = step.Async;
                    stepData.StateName       = saga.ExecutionState.CurrentState;
                    stepData.StepName        = saga.ExecutionState.CurrentStep;
                    stepData.Event           = saga.ExecutionState.CurrentEvent;
                    saga.ExecutionState.History.Add(stepData);
                }
                else
                {
                }

                stepData.ExecutionData = new StepExecutionData
                {
                };
            }

            return(stepData);
        }
        private async Task <ISaga> ExecuteSaga(
            ISagaEvent @event, ISagaModel model,
            ISaga saga,
            Guid sagaID,
            IDictionary <string, object> executionValues,
            bool resume)
        {
            bool sagaStarted = false;

            try
            {
                serviceProvider.
                GetRequiredService <ObservableRegistrator>().
                Initialize();

                await messageBus.
                Publish(new ExecutionStartMessage(SagaID.From(sagaID), model));

                sagaStarted = true;

                if (saga == null)
                {
                    saga = await sagaPersistance.Get(sagaID);
                }

                if (saga == null)
                {
                    throw new SagaInstanceNotFoundException();
                }

                if (saga.ExecutionState.IsDeleted)
                {
                    throw new CountNotExecuteDeletedSagaException(sagaID);
                }

                if (!resume)
                {
                    if (saga.IsIdle())
                    {
                        saga.ExecutionState.CurrentError = null;
                        saga.ExecutionState.ExecutionID  = ExecutionID.New();
                        if (model.HistoryPolicy == ESagaHistoryPolicy.StoreOnlyCurrentStep)
                        {
                            saga.ExecutionState.History.Clear();
                        }

                        saga.ExecutionValues.
                        Set(executionValues);

                        saga.ExecutionState.
                        CurrentEvent = @event ?? new EmptyEvent();
                    }
                    else
                    {
                        throw new SagaNeedToBeResumedException(saga.Data.ID);
                    }

                    logger.
                    LogInformation($"Executing saga: {saga.Data.ID}");
                }
                else
                {
                    logger.
                    LogInformation($"Resuming saga: {saga.Data.ID}");
                }

                ExecuteActionCommandHandler handler = serviceProvider.
                                                      GetRequiredService <ExecuteActionCommandHandler>();

                return(await handler.Handle(new ExecuteActionCommand
                {
                    Async = AsyncExecution.False(),
                    Saga = saga,
                    Model = model
                }));
            }
            catch (Exception ex)
            {
                if (sagaStarted)
                {
                    await messageBus.Publish(
                        new ExecutionEndMessage(SagaID.From(sagaID)));
                }

                if (ex is SagaStepException sagaStepException && sagaStepException?.OriginalException != null)
                {
                    throw sagaStepException.OriginalException;
                }

                throw;
            }
        }
Пример #18
0
 public ExecutionStartMessage(ISaga saga, ISagaModel model)
 {
     Saga  = saga;
     Model = model;
 }
 public AnnotatedSagaManager(ISagaRepository <T> sagaRepository, Func <T> sagaFactory, ISagaModel sagaMetaModel, IListenerInvocationErrorHandler listenerInvocationErrorHandler)
     : base(sagaRepository, sagaFactory, listenerInvocationErrorHandler)
 {
     _sagaMetaModel = sagaMetaModel;
 }
//        private readonly ResourceInjector injector;

        public AnnotatedSagaRepository(ISagaStore sagaStore, ISagaModel sagaModel, ILockFactory lockFactory) : base(lockFactory)
        {
            _sagaStore = sagaStore;
            _sagaModel = sagaModel;
        }
 public ExecutionStartMessage(SagaID saga, ISagaModel model)
 {
     SagaID     = saga;
     this.Model = model;
 }
Пример #22
0
        public async Task ResumeAll()
        {
            isResuming++;
            try
            {
                IList <Guid> ids = await sagaPersistance.GetUnfinished();

                List <string> invalidModels = new List <string>();
                foreach (Guid id in ids)
                {
                    ISaga saga = await sagaPersistance.Get(id);

                    ISagaModel model = sagaRegistrator.FindModelByName(saga.ExecutionInfo.ModelName);

                    if (model == null)
                    {
                        invalidModels.Add(saga.ExecutionInfo.ModelName);
                    }
                }

                if (invalidModels.Count > 0)
                {
                    throw new Exception($"Saga models {string.Join(", ", invalidModels.Distinct().ToArray())} not found");
                }

                foreach (Guid id in ids)
                {
                    ISaga saga = await sagaPersistance.
                                 Get(id);

                    ISagaModel model = sagaRegistrator.
                                       FindModelByName(saga.ExecutionInfo.ModelName);

                    logger.
                    LogInformation($"Trying to resume the saga {id}");

                    bool isCompensating = saga.ExecutionState.IsCompensating;
                    var  error          = saga?.ExecutionState?.CurrentError;

                    try
                    {
                        await ExecuteSaga(
                            new EmptyEvent(),
                            model,
                            saga,
                            saga.Data.ID,
                            null,
                            true,
                            null);

                        logger.
                        LogInformation($"The saga {id} has been resumed");
                    }
                    catch (Exception ex)
                    {
                        // ZROBIĆ TAK ABY WYJATEK POKAZYWAL SIE TYLKO WTEDY, GDY
                        // SAGA ZOSTAŁA WZNOWIONA I BYŁ BŁĄD
                        // SAGA ZOSTAŁA WZNOWIONA I BEZ BLEDU - TYLKO INFORMACJA
                        // GDY SAGA COMPENSOWANA TO NIE POKAZUJEMY BLEDU - TYLKO INFORMACJE
                        var currentSaga = await sagaPersistance.Get(id);

                        var currentError = currentSaga?.ExecutionState?.CurrentError;

                        if (isCompensating)
                        {
                            if (error?.Message != currentError?.Message)
                            {
                                logger.
                                LogError(ex, $"The saga {id} has been compensated, but an error has occurred");
                            }
                            else
                            {
                                logger.
                                LogInformation($"The saga {id} has been compensated");
                            }
                        }
                        else
                        {
                            logger.
                            LogError(ex, $"The saga {id} has been resumed, but an error has occurred");
                        }
                    }
                }
            }
            finally
            {
                isResuming--;
            }
        }
 public SagaSettingsBuilder(ISagaModel model)
 {
     this.model = model;
 }
 public void Register(ISagaModel model)
 {
     registeredModels.Add(model);
 }
 public static SagaActions FindActionsByState(
     this ISagaModel model, string state)
 {
     return(new SagaActions(
                model.Actions.Where(s => s.State == state)));
 }