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); }
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(); }
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(); }
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); }
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)); }
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 }); }
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(); }
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 })); } } } }
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; } }