Exemplo n.º 1
0
 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;
            }
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 5
0
        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);
        }
Exemplo n.º 6
0
        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());
        }
Exemplo n.º 7
0
 /// <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);
     });
 }
Exemplo n.º 8
0
 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);
        }
Exemplo n.º 10
0
        public Task <IEnumerable <ISagaCommand> > RunAsync(ISagaEvent sagaEvent)
        {
            if (sagaEvent is null)
            {
                throw new ArgumentNullException(nameof(sagaEvent));
            }

            return(GetOrCreateProcessor().RunAsync(sagaEvent));
        }
Exemplo n.º 11
0
        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));
        }
Exemplo n.º 12
0
        public async Task RunAsync_EventIsNull_ThrowArgumentNull()
        {
            // Arrange
            var        sagaProcessor = CreateSagaProcessor();
            ISagaEvent sagaEvent     = null;

            // Assert
            await Assert
            .ThrowsAsync <ArgumentNullException>(() => sagaProcessor.RunAsync(sagaEvent))
            .ConfigureAwait(false);
        }
Exemplo n.º 13
0
 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++;
     }
 }
Exemplo n.º 14
0
        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));
        }
Exemplo n.º 15
0
        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));
        }
Exemplo n.º 16
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;
            }
        }
Exemplo n.º 17
0
 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();
     }
 }
Exemplo n.º 18
0
        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));
        }
Exemplo n.º 19
0
        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);
            }
        }
Exemplo n.º 21
0
 /// <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);
 }
Exemplo n.º 22
0
 /// <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);
 }
Exemplo n.º 23
0
 /// <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;
 }
Exemplo n.º 24
0
 /// <summary>
 /// Publish the saved <paramref name="event"/>.
 /// </summary>
 protected virtual void PublishEvent(ISagaEvent <TAuthenticationToken> @event)
 {
     Publisher.Publish(@event);
 }
Exemplo n.º 25
0
        /// <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);
            }
        }
Exemplo n.º 26
0
 private void ApplyChange(ISagaEvent <TAuthenticationToken> @event, bool isEventReplay)
 {
     ApplyChanges(new[] { @event }, isEventReplay);
 }
Exemplo n.º 27
0
 /// <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();
 }
Exemplo n.º 28
0
        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;
            }
        }
Exemplo n.º 30
0
        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;
            }
        }