Exemple #1
0
        public void LoadSagas(IEnumerable <Type> sagaTypes)
        {
            foreach (var sagaType in sagaTypes)
            {
                if (_sagaDetails.ContainsKey(sagaType))
                {
                    _log.Warning($"Saga type '{sagaType.PrettyPrint()}' has already been added, skipping it this time");
                    continue;
                }

                var sagaDetails = SagaDetails.From(sagaType);
                _sagaDetails[sagaType] = sagaDetails;

                foreach (var aggregateEventType in sagaDetails.AggregateEventTypes)
                {
                    var sagaDetailsList = _sagaDetailsByAggregateEvent.GetOrAdd(
                        aggregateEventType,
                        new List <SagaDetails>());

                    sagaDetailsList.Add(sagaDetails);
                }
            }
        }
Exemple #2
0
        private Task UpdateSagaAsync(
            ISaga saga,
            IDomainEvent domainEvent,
            SagaDetails details,
            CancellationToken cancellationToken)
        {
            if (saga.State == SagaState.Completed)
            {
                _log.Debug(() => string.Format(
                               "Saga '{0}' is completed, skipping processing of '{1}'",
                               details.SagaType.PrettyPrint(),
                               domainEvent.EventType.PrettyPrint()));
                return(Task.FromResult(0));
            }

            if (saga.State == SagaState.New && !details.IsStartedBy(domainEvent.EventType))
            {
                _log.Debug(() => string.Format(
                               "Saga '{0}' isn't started yet and not started by '{1}', skipping",
                               details.SagaType.PrettyPrint(),
                               domainEvent.EventType.PrettyPrint()));
                return(Task.FromResult(0));
            }

            var sagaUpdaterType = typeof(ISagaUpdater <, , ,>).MakeGenericType(
                domainEvent.AggregateType,
                domainEvent.IdentityType,
                domainEvent.EventType,
                details.SagaType);
            var sagaUpdater = (ISagaUpdater)_resolver.Resolve(sagaUpdaterType);

            return(sagaUpdater.ProcessAsync(
                       saga,
                       domainEvent,
                       SagaContext.Empty,
                       cancellationToken));
        }
Exemple #3
0
        private async Task ProcessSagaAsync(
            IDomainEvent domainEvent,
            ISagaId sagaId,
            SagaDetails details,
            CancellationToken cancellationToken)
        {
            try
            {
                _log.Verbose(() => $"Loading saga '{details.SagaType.PrettyPrint()}' with ID '{sagaId}'");

                await _sagaStore.UpdateAsync(
                    sagaId,
                    details.SagaType,
                    domainEvent.Metadata.SourceId,
                    (s, c) => UpdateSagaAsync(s, domainEvent, details, c),
                    cancellationToken)
                .ConfigureAwait(false);
            }
            catch (Exception e)
            {
                var handled = await _sagaErrorHandler.HandleAsync(
                    sagaId,
                    details,
                    e,
                    cancellationToken)
                              .ConfigureAwait(false);

                if (handled)
                {
                    return;
                }

                _log.Error(e, $"Failed to process domain event '{domainEvent.EventType}' for saga '{details.SagaType.PrettyPrint()}'");
                throw;
            }
        }
Exemple #4
0
        private async Task ProcessSagaAsync(
            IDomainEvent domainEvent,
            ISagaId sagaId,
            SagaDetails details,
            CancellationToken cancellationToken)
        {
            try
            {
                _log.Verbose(() => $"Loading saga '{details.SagaType.PrettyPrint()}' with ID '{sagaId}'");

                await _sagaStore.UpdateAsync(
                    sagaId,
                    details.SagaType,
                    domainEvent.Metadata.EventId,
                    (s, c) => UpdateSagaAsync(s, domainEvent, details, c),
                    cancellationToken)
                .ConfigureAwait(false);
            }
            catch (Exception e)
            {
                // Search for a specific SagaErrorHandler<Saga> based on saga type
                ISagaErrorHandler specificSagaErrorHandler = _sagaErrorHandlerFactory(details.SagaType);

                bool handled = specificSagaErrorHandler != null ?
                               await specificSagaErrorHandler.HandleAsync(sagaId, details, e, cancellationToken).ConfigureAwait(false) :
                               await _sagaErrorHandler.HandleAsync(sagaId, details, e, cancellationToken).ConfigureAwait(false);

                if (handled)
                {
                    return;
                }

                _log.Error(e, $"Failed to process domain event '{domainEvent.EventType}' for saga '{details.SagaType.PrettyPrint()}'");
                throw;
            }
        }
Exemple #5
0
        private async Task UpdateSagaAsync(
            ISaga saga,
            IDomainEvent domainEvent,
            SagaDetails details,
            CancellationToken cancellationToken)
        {
            if (saga.State == SagaState.Completed)
            {
                _log.Debug(() => string.Format(
                               "Saga '{0}' is completed, skipping processing of '{1}'",
                               details.SagaType.PrettyPrint(),
                               domainEvent.EventType.PrettyPrint()));
                return;
            }

            if (saga.State == SagaState.New && !details.IsStartedBy(domainEvent.EventType))
            {
                _log.Debug(() => string.Format(
                               "Saga '{0}' isn't started yet and not started by '{1}', skipping",
                               details.SagaType.PrettyPrint(),
                               domainEvent.EventType.PrettyPrint()));
                return;
            }

            var sagaUpdaterType = typeof(ISagaUpdater <, , ,>).MakeGenericType(
                domainEvent.AggregateType,
                domainEvent.IdentityType,
                domainEvent.EventType,
                details.SagaType);
            var sagaUpdater = (ISagaUpdater)_resolver.Resolve(sagaUpdaterType);

            await _sagaUpdateLog.BeforeUpdateAsync(
                saga,
                domainEvent,
                details,
                cancellationToken)
            .ConfigureAwait(false);

            try
            {
                await sagaUpdater.ProcessAsync(
                    saga,
                    domainEvent,
                    SagaContext.Empty,
                    cancellationToken)
                .ConfigureAwait(false);

                await _sagaUpdateLog.UpdateSucceededAsync(
                    saga,
                    domainEvent,
                    details,
                    cancellationToken)
                .ConfigureAwait(false);
            }
            catch (Exception e)
            {
                if (!await _sagaUpdateLog.HandleUpdateFailedAsync(
                        saga,
                        domainEvent,
                        details,
                        e,
                        cancellationToken)
                    .ConfigureAwait(false))
                {
                    throw;
                }
            }
        }
Exemple #6
0
        private async Task UpdateSagaAsync(
            ISaga saga,
            IDomainEvent domainEvent,
            SagaDetails details,
            CancellationToken cancellationToken)
        {
            if (saga.State == SagaState.Completed)
            {
                _logger.LogTrace(
                    "Saga {SagaType} is completed, skipping processing of {DomainEventType}",
                    details.SagaType.PrettyPrint(),
                    domainEvent.EventType.PrettyPrint());
                return;
            }

            if (saga.State == SagaState.New && !details.IsStartedBy(domainEvent.EventType))
            {
                _logger.LogTrace(
                    "Saga {SagaType} isn't started yet and not started by {DomainEventType}, skipping",
                    details.SagaType.PrettyPrint(),
                    domainEvent.EventType.PrettyPrint());
                return;
            }

            var sagaUpdaterType = typeof(ISagaUpdater <, , ,>).MakeGenericType(
                domainEvent.AggregateType,
                domainEvent.IdentityType,
                domainEvent.EventType,
                details.SagaType);
            var sagaUpdater = (ISagaUpdater)_serviceProvider.GetRequiredService(sagaUpdaterType);

            await _sagaUpdateLog.BeforeUpdateAsync(
                saga,
                domainEvent,
                details,
                cancellationToken)
            .ConfigureAwait(false);

            try
            {
                await sagaUpdater.ProcessAsync(
                    saga,
                    domainEvent,
                    SagaContext.Empty,
                    cancellationToken)
                .ConfigureAwait(false);

                await _sagaUpdateLog.UpdateSucceededAsync(
                    saga,
                    domainEvent,
                    details,
                    cancellationToken)
                .ConfigureAwait(false);
            }
            catch (Exception e)
            {
                if (!await _sagaUpdateLog.HandleUpdateFailedAsync(
                        saga,
                        domainEvent,
                        details,
                        e,
                        cancellationToken)
                    .ConfigureAwait(false))
                {
                    throw;
                }
            }
        }