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