Example #1
0
        public async Task WHEN_sagaIsStoppedOnCreation_THEN_resumingSagaToInitState()
        {
            // given
            Guid id = Guid.NewGuid();

            ResumeSagaSettings.StopSagaExecution = true;
            await Assert.ThrowsAsync <SagaStopException>(async() =>
            {
                await sagaCoordinator.Publish(new CreateWithBreakEvent()
                {
                    ID = id
                });
            });

            // when
            ResumeSagaSettings.StopSagaExecution = false;
            await sagaCoordinator.
            Resume(id);

            // then
            ISaga persistedSaga = await sagaPersistance.Get(id);

            persistedSaga.IsIdle().ShouldBeTrue();
            persistedSaga.ExecutionState.CurrentState.ShouldBe(nameof(InitState));
            persistedSaga.ExecutionState.History.Count.ShouldBe(3);
        }
Example #2
0
        public async Task WHEN_stoppedSagaIsResumed_THEN_sagaShouldCompensateAndExecuteLastStep()
        {
            // given
            ResumeSagaSettings.StopSagaExecution = true;
            ISaga saga = await sagaCoordinator.Publish(new CreateEvent());

            await Assert.ThrowsAsync <SagaStopException>(async() =>
            {
                await sagaCoordinator.Publish(new ResumeSagaUpdateEvent()
                {
                    ID = saga.Data.ID
                });
            });

            ResumeSagaSettings.StopSagaExecution = false;
            //await sagaLocking.Banish(saga.Data.ID);

            // when
            await sagaCoordinator.
            Resume(saga.Data.ID);

            // then
            ISaga persistedSaga = await sagaPersistance.Get(saga.Data.ID);

            persistedSaga.ExecutionState.History.Where(s => s.ResumeData != null).Count().ShouldBe(1);
            persistedSaga.ExecutionState.History.Where(s => s.CompensationData != null).Count().ShouldBe(0);
            persistedSaga.ExecutionState.History.Where(s => s.ExecutionData != null).Count().ShouldBe(3);
            persistedSaga.IsIdle().ShouldBeTrue();
        }
Example #3
0
        public async Task WHEN_stoppedSagaIsResumed_THEN_sagaShouldMoveToValidState()
        {
            // given
            ResumeSagaSettings.StopSagaExecution = true;
            ISaga saga = await sagaCoordinator.Publish(new CreateEvent());

            await Assert.ThrowsAsync <SagaStopException>(async() =>
            {
                await sagaCoordinator.Publish(new ResumeSagaUpdateEvent()
                {
                    ID = saga.Data.ID
                });
            });

            ResumeSagaSettings.StopSagaExecution = false;
            //await sagaLocking.Banish(saga.Data.ID);

            // when
            await sagaCoordinator.
            Resume(saga.Data.ID);

            // then
            ISaga persistedSaga = await sagaPersistance.Get(saga.Data.ID);

            persistedSaga.IsIdle().ShouldBeTrue();
        }
Example #4
0
        public async Task WHEN_sagaIsStoppedOnInvalidCreation_THEN_resumingShouldRemoveSaga()
        {
            // given
            Guid id = Guid.NewGuid();

            ResumeSagaSettings.StopSagaExecution = true;
            await Assert.ThrowsAsync <SagaStopException>(async() =>
            {
                await sagaCoordinator.Publish(new CreateWithErrorEvent()
                {
                    ID = id
                });
            });

            //await sagaLocking.Banish(id);

            // when
            await Assert.ThrowsAsync <Exception>(async() =>
            {
                ResumeSagaSettings.StopSagaExecution = false;
                await sagaCoordinator.
                Resume(id);
            });

            // then
            ISaga persistedSaga = await sagaPersistance.Get(id);

            persistedSaga.IsIdle().ShouldBeTrue();
            persistedSaga.ExecutionState.IsDeleted.ShouldBeTrue();
            persistedSaga.ExecutionState.CurrentState.ShouldBe("");
            persistedSaga.ExecutionState.History.Count.ShouldBe(3);
        }
        public async Task WaitForIdle(
            Guid id, SagaWaitOptions waitOptions = null)
        {
            if (waitOptions == null)
            {
                waitOptions = new SagaWaitOptions();
            }

            try
            {
                bool isSagaInIdleState = false;

                messageBus.Subscribe <ExecutionEndMessage>(this, mesage =>
                {
                    if (mesage.SagaId.Value == id)
                    {
                        ISaga saga = sagaPersistance.Get(id).GetAwaiter().GetResult();
                        if (saga?.IsIdle() == true)
                        {
                            isSagaInIdleState = true;
                        }
                    }
                    return(Task.CompletedTask);
                });

                ISaga saga = await sagaPersistance.Get(id);

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

                if (saga.IsIdle())
                {
                    return;
                }

                Stopwatch stopwatch = Stopwatch.StartNew();
                while (!isSagaInIdleState)
                {
                    await Task.Delay(250);

                    if (stopwatch.Elapsed >= waitOptions.Timeout)
                    {
                        throw new TimeoutException();
                    }
                }
            }
            finally
            {
                messageBus.Unsubscribe <ExecutionEndMessage>(this);
            }
        }
        public async Task WHEN_sagaIsStopped_THEN_sagaShouldNotBeInIdleState()
        {
            // given
            var @event = new SagaCreateWithDoStepEvent();

            // when
            ISaga saga = await sagaCoordinator.Publish(@event);

            // then
            ISaga persistedSaga = await sagaPersistance.Get(saga.Data.ID);

            persistedSaga.IsIdle().ShouldBeTrue();
            persistedSaga.ExecutionState.History.Count.ShouldBe(7);
        }
Example #7
0
        public static ISagaStep FindStepForExecutionStateAndEvent(
            this ISagaActions actions, ISaga saga)
        {
            ISagaActions foundActions = actions.
                                        FindActionsByState(saga.ExecutionState.GetExecutionState());

            Type eventType = saga.ExecutionState.CurrentEvent.GetType();

            if (saga.IsIdle() && !eventType.Is <EmptyEvent>())
            {
                return(FindStepForEventType(saga, eventType, foundActions));
            }

            return(FindStepForCurrentState(saga, foundActions));
        }
Example #8
0
        public async Task <ISagaRunningState> GetSagaState(Guid id)
        {
            ISaga saga = await sagaPersistance.Get(id);

            if (saga == null)
            {
                return(null);
            }

            return(new SagaRunningState
            {
                IsRunning = !saga.IsIdle(),
                IsResuming = saga.ExecutionState.IsResuming,
                IsCompensating = saga.ExecutionState.IsCompensating
            });
        }
Example #9
0
        public async Task WHEN_sagaIsStopped_THEN_sagaShouldNotBeInIdleState()
        {
            // given
            ResumeSagaSettings.StopSagaExecution = true;
            ISaga saga = await sagaCoordinator.Publish(new CreateEvent());

            // when
            await sagaCoordinator.Publish(new ResumeSagaUpdateEvent()
            {
                ID = saga.Data.ID
            });

            // then
            ISaga persistedSaga = await sagaPersistance.Get(saga.Data.ID);

            persistedSaga.IsIdle().ShouldBeFalse();
        }
Example #10
0
        private async Task <ISaga> DispatchStepSync(
            ExecuteStepCommand command)
        {
            using (IServiceScope scope = serviceScopeFactory.CreateScope())
            {
                ExecuteStepCommandHandler stepExecutor = ActivatorUtilities.
                                                         CreateInstance <ExecuteStepCommandHandler>(scope.ServiceProvider);

                ISaga saga = await stepExecutor.
                             Handle(command);

                if (saga == null)
                {
                    await messageBus.Publish(
                        new ExecutionEndMessage(SagaID.From(command.Saga.Data.ID)));

                    return(null);
                }
                else
                {
                    if (saga.IsIdle())
                    {
                        await messageBus.Publish(
                            new ExecutionEndMessage(SagaID.From(saga.Data.ID)));

                        if (saga.HasError())
                        {
                            throw saga.ExecutionState.CurrentError;
                        }

                        return(saga);
                    }
                    else
                    {
                        return(await Handle(new ExecuteActionCommand()
                        {
                            Async = AsyncExecution.False(),
                            Saga = saga,
                            Model = command.Model
                        }));
                    }
                }
            }
        }
Example #11
0
        public async Task WHEN_sagaIsStoppedOnCreationSecondSaga_THEN_resumingSagaToInitState()
        {
            // given
            Guid id    = Guid.NewGuid();
            Guid newId = Guid.NewGuid();

            ResumeSagaSettings.StopSagaExecution = true;
            await Assert.ThrowsAsync <SagaStopException>(async() =>
            {
                await sagaCoordinator.Publish(new CreateEvent()
                {
                    ID = id
                });
                await sagaCoordinator.Publish(new CreateNewSagaEvent()
                {
                    ID = id, NewID = newId
                });
            });

            //await sagaLocking.Banish(id);

            // when
            ResumeSagaSettings.StopSagaExecution = false;
            await sagaCoordinator.
            ResumeAll();

            // then
            ISaga persistedSaga = await sagaPersistance.Get(id);

            persistedSaga.IsIdle().ShouldBeTrue();
            persistedSaga.ExecutionState.CurrentState.ShouldBe(nameof(SecondState));

            ISaga persistedSagaNew = await sagaPersistance.Get(newId);

            persistedSagaNew.IsIdle().ShouldBeTrue();
            persistedSagaNew.ExecutionState.CurrentState.ShouldBe(nameof(SecondState));
        }
        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;
            }
        }