public async Task Compensate( IServiceProvider serviceProvider, IExecutionContext context, ISagaEvent @event, IStepData stepData) { }
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 ExecuteStep(ISaga saga, ISagaStep sagaStep, StepData stepData) { ISagaEvent @event = stepData.Event; if (@event is EmptyEvent) { @event = null; } Type executionContextType = typeof(ExecutionContext <>).ConstructGenericType(saga.Data.GetType()); IExecutionContext context = (IExecutionContext)ActivatorUtilities.CreateInstance(serviceProvider, executionContextType, saga.Data, saga.ExecutionInfo, saga.ExecutionState, saga.ExecutionValues, stepData.ExecutionValues); if (saga.ExecutionState.IsResuming) { await sagaStep.Compensate(serviceProvider, context, @event, stepData); } else if (saga.ExecutionState.IsCompensating) { await sagaStep.Compensate(serviceProvider, context, @event, stepData); } else { await sagaStep.Execute(serviceProvider, context, @event, stepData); } }
public async Task Execute( IServiceProvider serviceProvider, IExecutionContext context, ISagaEvent @event, IStepData stepData) { if (typeof(TExecuteEvent) == typeof(EmptyEvent)) { return; } ISagaCoordinator sagaCoordinator = serviceProvider. GetRequiredService <ISagaCoordinator>(); IExecutionContext <TSagaData> contextForAction = (IExecutionContext <TSagaData>)context; TExecuteEvent executionEvent = new TExecuteEvent(); if (action != null) { await action(contextForAction, executionEvent); } await sagaCoordinator. Publish(executionEvent, contextForAction.ExecutionValues); }
public async Task <IEnumerable <ISagaCommand> > RunAsync(ISagaEvent sagaEvent, ISagaStepAdapter step) { var eventReference = new SagaReference(step.Version, step.Index, SagaMessageType.Event, sagaEvent.ProcessId, sagaEvent.TransactionId, sagaEvent); await _store .AddReferences(eventReference) .ConfigureAwait(false); var commands = await step .RunAsync(sagaEvent) .ConfigureAwait(false); if (commands is null) { return(Enumerable.Empty <ISagaCommand>()); } var commandReferences = commands .Select(cmnd => new SagaReference(step.Version, step.Index, SagaMessageType.Command, cmnd.ProcessId, cmnd.TransactionId, cmnd)) .ToArray(); await _store .AddReferences(commandReferences) .ConfigureAwait(false); return(commands); }
public async Task Execute( IServiceProvider serviceProvider, IExecutionContext context, ISagaEvent @event, IStepData stepData) { if (typeof(TExecuteEvent) == typeof(EmptyEvent)) { return; } ISagaInternalCoordinator sagaCoordinator = serviceProvider. GetRequiredService <ISagaCoordinator>() as ISagaInternalCoordinator; IExecutionContext <TSagaData> contextForAction = (IExecutionContext <TSagaData>)context; TExecuteEvent executionEvent = new TExecuteEvent(); if (ActionDelegate != null) { await ActionDelegate(contextForAction, executionEvent); } ISaga newSaga = await sagaCoordinator. Publish(executionEvent, contextForAction.ExecutionValues, contextForAction.Data.ID, new SagaRunOptions()); }
/// <summary> /// Publish the saved <paramref name="event"/> asynchronously on <see cref="EventPublisher"/>, /// then calls <see cref="SagaRepository{TAuthenticationToken}.PublishEvent"/> /// </summary> protected override void PublishEvent(ISagaEvent <TAuthenticationToken> @event) { Task.Factory.StartNewSafely(() => { EventPublisher.Publish(@event); base.PublishEvent(@event); }); }
public async Task Execute( IServiceProvider serviceProvider, IExecutionContext context, ISagaEvent @event, IStepData stepData) { (context.ExecutionState as SagaExecutionState).IsBreaked = true; }
public bool IsResponsible(ISagaEvent sagaEvent) { if (!(sagaEvent is TEvent converted)) { return(false); } return(_customValidation?.Invoke(converted) ?? true); }
public Task <IEnumerable <ISagaCommand> > RunAsync(ISagaEvent sagaEvent) { if (sagaEvent is null) { throw new ArgumentNullException(nameof(sagaEvent)); } return(GetOrCreateProcessor().RunAsync(sagaEvent)); }
public async Task <ISagaStepConfiguration> ResolveAsync(ISagaEvent sagaEvent, IDictionary <ISagaVersion, IList <ISagaStepConfiguration> > versions) { var references = await _sagaEventStore .GetReferencesAsync(sagaEvent.ProcessId) .ConfigureAwait(false); var resolverFunc = _getVersionFunc(_sagaVersionResolver, references).Compose(_getStepFunc(_sagaStepResolver, sagaEvent, references)); return(resolverFunc(versions)); }
public async Task RunAsync_EventIsNull_ThrowArgumentNull() { // Arrange var sagaProcessor = CreateSagaProcessor(); ISagaEvent sagaEvent = null; // Assert await Assert .ThrowsAsync <ArgumentNullException>(() => sagaProcessor.RunAsync(sagaEvent)) .ConfigureAwait(false); }
private void ApplyChange(ISagaEvent <TAuthenticationToken> @event, bool isEventReplay) { this.AsDynamic().Apply(@event); if (!isEventReplay) { Changes = new ReadOnlyCollection <ISagaEvent <TAuthenticationToken> >(new[] { @event }.Concat(Changes).ToList()); } else { Id = @event.Id; Version++; } }
public Task <IEnumerable <ISagaCommand> > RunAsync(ISagaEvent sagaEvent) { if (sagaEvent is null) { throw new ArgumentNullException(nameof(sagaEvent)); } if (!(sagaEvent is TEvent converted)) { throw new ArgumentOutOfRangeException($"{nameof(sagaEvent)} is not of type {typeof(TEvent).Name}."); } return(_step.RunAsync(converted)); }
public void Create_EventNull_ThrowArgumentNull() { // Arrange var func = new SagaStepResolver().Create(); var configurations = new List <ISagaStepConfiguration> { new SagaStepConfiguration <SagaEvent01, SagaStep01Mock>(new SagaVersion("1.0.0"), 0, null) }; ISagaEvent sagaEvent = null; // Assert Assert.Throws <ArgumentNullException>(() => func(sagaEvent, null, configurations)); }
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; } }
private void ApplyChange(ISagaEvent <TAuthenticationToken> @event, bool isEventReplay) { Lock.EnterWriteLock(); try { this.AsDynamic().Apply(@event.Event); if (!isEventReplay) { Changes = new ReadOnlyCollection <ISagaEvent <TAuthenticationToken> >(Changes.Concat(new[] { @event }).ToList()); } else { Id = @event.Id; Version++; } } finally { Lock.ExitWriteLock(); } }
public async Task <IEnumerable <ISagaCommand> > RunAsync(ISagaEvent sagaEvent) { if (sagaEvent is null) { throw new ArgumentNullException(nameof(sagaEvent)); } if (_steps.Count.Equals(0)) { throw new InvalidOperationException($"No steps configured for reference id {sagaEvent.ProcessId}."); } var configuration = await _resolver .ResolveAsync(sagaEvent, _steps) .ConfigureAwait(false); var step = configuration.Create(_provider); return(await _process .RunAsync(sagaEvent, step) .ConfigureAwait(false)); }
public async Task ProcessActionAsync <TMessage>( TMessage message, ISagaEvent <TMessage> sagaEvent, ISagaContext context, Func <TMessage, Task> onCompleted = null, Func <TMessage, Task> onRejected = null) { var saga = (ISaga)sagaEvent; await Semaphore.WaitAsync(); try { await sagaEvent.HandleAsync(message, context); } catch (Exception ex) { context.AddError(ex); saga.Reject(); } finally { Semaphore.Release(); } if (saga.State is SagaState.Rejected) { await onRejected(message); //compensate } else if (saga.State is SagaState.Completed) { await onCompleted(message); } }
public async Task Compensate(IServiceProvider serviceProvider, IExecutionContext context, ISagaEvent @event, IStepData stepData) { IExecutionContext <TSagaData> contextForAction = (IExecutionContext <TSagaData>)context; if (compensation != null) { await compensation(contextForAction); } }
/// <summary> /// Dynamically calls the "Apply" method, passing it the <see cref="ISagaEvent{TAuthenticationToken}.Event"/> of the provided <paramref name="sagaEvent"/>. /// </summary> protected virtual void Apply(ISagaEvent <TAuthenticationToken> sagaEvent) { this.AsDynamic().Apply(sagaEvent.Event); }
/// <summary> /// Call the "Apply" method with a signature matching the provided <paramref name="event"/> without using event replay to this instance. /// </summary> /// <remarks> /// This means a method named "Apply", with return type void and one parameter must exist to be applied. /// If no method exists, nothing is applied /// The parameter type must match exactly the <see cref="Type"/> of the provided <paramref name="event"/>. /// </remarks> protected virtual void ApplyChange(ISagaEvent <TAuthenticationToken> @event) { ApplyChange(@event, false); }
/// <summary> /// Sets the <see cref="IEvent{TAuthenticationToken}.Id"/> from <see cref="ISagaEvent{TAuthenticationToken}.Event"/> back onto <paramref name="sagaEvent"/>. /// </summary> protected virtual void SetId(ISagaEvent <TAuthenticationToken> sagaEvent) { sagaEvent.Id = sagaEvent.Event.Id; }
/// <summary> /// Publish the saved <paramref name="event"/>. /// </summary> protected virtual void PublishEvent(ISagaEvent <TAuthenticationToken> @event) { Publisher.Publish(@event); }
/// <summary> /// Publishes the provided <paramref name="event"/> on the event bus. /// </summary> public virtual void Publish <TEvent>(TEvent @event) where TEvent : IEvent <TAuthenticationToken> { Type eventType = @event.GetType(); string eventName = eventType.FullName; ISagaEvent <TAuthenticationToken> sagaEvent = @event as ISagaEvent <TAuthenticationToken>; if (sagaEvent != null) { eventName = string.Format("Cqrs.Events.SagaEvent[{0}]", sagaEvent.Event.GetType().FullName); } DateTimeOffset startedAt = DateTimeOffset.UtcNow; Stopwatch mainStopWatch = Stopwatch.StartNew(); string responseCode = "200"; bool wasSuccessfull = false; IDictionary <string, string> telemetryProperties = new Dictionary <string, string> { { "Type", "InProcessBus" } }; string telemetryName = string.Format("{0}/{1}/{2}", eventName, @event.GetIdentity(), @event.Id); var telemeteredEvent = @event as ITelemeteredMessage; if (telemeteredEvent != null) { telemetryName = telemeteredEvent.TelemetryName; } telemetryName = string.Format("Event/{0}", telemetryName); try { if (@event.Frameworks != null && @event.Frameworks.Contains("Built-In")) { Logger.LogInfo("The provided event has already been processed by the Built-In bus.", string.Format("{0}\\PrepareAndValidateEvent({1})", GetType().FullName, eventType.FullName)); return; } if (@event.AuthenticationToken == null || @event.AuthenticationToken.Equals(default(TAuthenticationToken))) { @event.AuthenticationToken = AuthenticationTokenHelper.GetAuthenticationToken(); } @event.CorrelationId = CorrelationIdHelper.GetCorrelationId(); if (string.IsNullOrWhiteSpace(@event.OriginatingFramework)) { @event.TimeStamp = DateTimeOffset.UtcNow; @event.OriginatingFramework = "Built-In"; } var frameworks = new List <string>(); if (@event.Frameworks != null) { frameworks.AddRange(@event.Frameworks); } frameworks.Add("Built-In"); @event.Frameworks = frameworks; bool isRequired; if (!ConfigurationManager.TryGetSetting(string.Format("{0}.IsRequired", eventName), out isRequired)) { isRequired = true; } IEnumerable <Action <IMessage> > handlers = Routes.GetHandlers(@event, isRequired).Select(x => x.Delegate).ToList(); // This check doesn't require an isRequired check as there will be an exception raised above and handled below. if (!handlers.Any()) { Logger.LogDebug(string.Format("An event handler for '{0}' is not required.", eventName)); } foreach (Action <IMessage> handler in handlers) { IList <IEvent <TAuthenticationToken> > events; if (EventWaits.TryGetValue(@event.CorrelationId, out events)) { events.Add(@event); } handler(@event); } Logger.LogInfo(string.Format("An event was sent of type {0}.", eventName)); wasSuccessfull = true; } catch (Exception exception) { responseCode = "500"; Logger.LogError("An issue occurred while trying to publish an event.", exception: exception, metaData: new Dictionary <string, object> { { "Event", @event } }); throw; } finally { mainStopWatch.Stop(); TelemetryHelper.TrackDependency("InProcessBus/EventBus", "Event", telemetryName, null, startedAt, mainStopWatch.Elapsed, responseCode, wasSuccessfull, telemetryProperties); } }
private void ApplyChange(ISagaEvent <TAuthenticationToken> @event, bool isEventReplay) { ApplyChanges(new[] { @event }, isEventReplay); }
/// <summary> /// Sets the <see cref="IEvent{TAuthenticationToken}.Id"/> from <see cref="ISagaEvent{TAuthenticationToken}.Event"/> back onto <paramref name="sagaEvent"/>. /// </summary> protected virtual void SetId(ISagaEvent <TAuthenticationToken> sagaEvent) { sagaEvent.Rsn = sagaEvent.Event.GetIdentity(); }
public async Task Execute(IServiceProvider serviceProvider, IExecutionContext context, ISagaEvent @event, IStepData stepData) { IExecutionContext <TSagaData> contextForAction = (IExecutionContext <TSagaData>)context; TEventHandler activity = (TEventHandler)ActivatorUtilities.CreateInstance(serviceProvider, typeof(TEventHandler)); if (activity != null) { await activity.Execute(contextForAction, (TEvent)@event); } }
public async Task Execute(IServiceProvider serviceProvider, IExecutionContext context, ISagaEvent @event, IStepData stepData) { IExecutionContext <TSagaData> contextForAction = (IExecutionContext <TSagaData>)context; if (action != null) { bool result = await action(contextForAction); stepData.ExecutionData.ConditionResult = result; } else { stepData.ExecutionData.ConditionResult = false; } }
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; } }