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; }
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); }
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; }
public AsyncStepCompletedMessage(SagaID sagaID, string currentState, string currentStep, bool isCompensating, ISagaModel model) { SagaID = sagaID; CurrentState = currentState; CurrentStep = currentStep; IsCompensating = isCompensating; Model = model; }
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; }
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); }
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)); }
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; } }
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; }
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))); }