public void Send <TMessage>(Expression <Func <T, bool> > filter, ISagaPolicy <T, TMessage> policy, TMessage message, Action <T> consumerAction)
            where TMessage : class
        {
            using (ISession session = _sessionFactory.OpenSession())
                using (ITransaction transaction = session.BeginTransaction())
                {
                    T[] existingSagas = session.Linq <T>()
                                        .Where(filter).ToArray();

                    bool foundExistingSagas = SendMessageToExistingSagas(existingSagas, policy, consumerAction, message, session.Delete);
                    if (foundExistingSagas)
                    {
                        transaction.Commit();
                        return;
                    }

                    SendMessageToNewSaga(policy, message, saga =>
                    {
                        consumerAction(saga);
                        session.Save(saga);
                    }, session.Delete);

                    transaction.Commit();
                }
        }
コード例 #2
0
        private async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance) where T : class
        {
            try
            {
                if (Log.IsDebugEnabled)
                {
                    Log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName,
                                    instance.CorrelationId, TypeMetadataCache <T> .ShortName);
                }

                var sagaConsumeContext = new V2DynamoDbEventStoreSagaConsumeContext <TSaga, T>(_connection, context, instance, _options);

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    await _connection.SaveEventsAsync(instance, _options);
                }
            }
            catch (SagaException sagaException)
            {
                if (Log.IsDebugEnabled)
                {
                    Log.Error(sagaException.Message, sagaException);
                }
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
        public async Task Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
                                   IPipe <SagaConsumeContext <TSaga, T> > next) where T : class
        {
            if (!context.CorrelationId.HasValue)
            {
                throw new SagaException("The CorrelationId was not specified", typeof(TSaga), typeof(T));
            }

            _logger.Debug($"SAGA: Send {context.Message.GetType().FullName}");

            var sagaId = context.CorrelationId.Value;

            if (policy.PreInsertInstance(context, out var instance))
            {
                await PreInsertSagaInstance <T>(instance, context.MessageId).ConfigureAwait(false);
            }

            if (instance == null)
            {
                instance = await GetSaga(sagaId);
            }

            if (instance == null)
            {
                var missingSagaPipe = new MissingPipe <T>(_connection, next);
                await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
            }
            else
            {
                await SendToInstance(context, policy, next, instance).ConfigureAwait(false);
            }
        }
コード例 #4
0
        async Task SendToInstance <T>(
            ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
            IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance
            )
            where T : class
        {
            try
            {
                var sagaConsumeContext = new EventStoreSagaConsumeContext <TSaga, T>(_connection, context, instance);

                sagaConsumeContext.LogUsed();

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    await _connection.PersistSagaInstance(instance, context, _getEventMetadata);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
コード例 #5
0
 public QuerySagaMessageConnector(IFilter <SagaConsumeContext <TSaga, TMessage> > consumeFilter, ISagaPolicy <TSaga, TMessage> policy,
                                  ISagaQueryFactory <TSaga, TMessage> queryFactory)
     : base(consumeFilter)
 {
     _policy       = policy;
     _queryFactory = queryFactory;
 }
コード例 #6
0
        Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            var interceptPipe   = new InterceptPipe <T>(_sagas, _received, next);
            var interceptPolicy = new InterceptPolicy <T>(_created, policy);

            return(_sagaRepository.Send(context, interceptPolicy, interceptPipe));
        }
コード例 #7
0
        static async Task SendToInstance <T>(ConsumeContext <T> context,
                                             ISagaPolicy <TSaga, T> policy, TSaga instance,
                                             IPipe <SagaConsumeContext <TSaga, T> > next, IDocumentSession session)
            where T : class
        {
            try
            {
                if (_log.IsDebugEnabled)
                {
                    _log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName, instance.CorrelationId,
                                     TypeMetadataCache <T> .ShortName);
                }

                var sagaConsumeContext = new MartenSagaConsumeContext <TSaga, T>(session, context, instance);

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    session.Store(instance);
                    session.SaveChanges();
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
コード例 #8
0
        public async Task SendQuery <T>(SagaQueryConsumeContext <TSaga, T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
            where T : class
        {
            try
            {
                List <TSaga> sagaInstances = await _collection.Find(context.Query.FilterExpression).ToListAsync().ConfigureAwait(false);

                if (!sagaInstances.Any())
                {
                    var missingPipe = new MissingPipe <TSaga, T>(_collection, next, _mongoDbSagaConsumeContextFactory);

                    await policy.Missing(context, missingPipe).ConfigureAwait(false);
                }
                else
                {
                    foreach (var instance in sagaInstances)
                    {
                        await SendToInstance(context, policy, next, instance).ConfigureAwait(false);
                    }
                }
            }
            catch (SagaException sex)
            {
                context.LogFault(sex);

                throw;
            }
            catch (Exception ex)
            {
                context.LogFault(ex);

                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), Guid.Empty, ex);
            }
        }
コード例 #9
0
 async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
 {
     using (_scope.BeginLifetimeScope(_name))
     {
         await _repository.Send(context, policy, next);
     }
 }
コード例 #10
0
 public SagaPolicyTestDecorator(ISagaPolicy <TSaga, TMessage> policy, Guid sagaId, SagaList <TSaga> created)
 {
     _policy  = policy;
     _sagaId  = sagaId;
     _created = created;
     _removed = new SagaList <TSaga>();
 }
コード例 #11
0
        async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance)
            where T : class
        {
            try
            {
                SagaConsumeContext <TSaga, T> sagaConsumeContext = _mongoDbSagaConsumeContextFactory.Create(_collection, context, instance);

                sagaConsumeContext.LogUsed();

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    await UpdateMongoDbSaga(context, instance).ConfigureAwait(false);
                }
            }
            catch (SagaException sex)
            {
                context.LogFault(this, sex, instance?.CorrelationId);

                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
コード例 #12
0
 public async Task Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next) where T : class
 {
     using (_container.CreateChildContainer())
     {
         await _repository.Send(context, policy, next).ConfigureAwait(false);
     }
 }
コード例 #13
0
ファイル: SagaRepository.cs プロジェクト: wastaz/MassTransit
        public async Task Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
            where T : class
        {
            var correlationId = context.CorrelationId ??
                                throw new SagaException("The CorrelationId was not specified", typeof(TSaga), typeof(T));

            try
            {
                await _repositoryContextFactory.Send(context, new SendSagaPipe <TSaga, T>(policy, next, correlationId)).ConfigureAwait(false);
            }
            catch (SagaException exception)
            {
                context.LogFault(this, exception);
                throw;
            }
            catch (DataException exception)
            {
                context.LogFault(this, exception);
                throw;
            }
            catch (Exception exception)
            {
                context.LogFault(this, exception);

                throw new SagaException(exception.Message, typeof(TSaga), typeof(T), Guid.Empty, exception);
            }
        }
コード例 #14
0
        public async Task SendQuery <T>(SagaQueryConsumeContext <TSaga, T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
            where T : class
        {
            using (var session = _sessionFactory.OpenSession())
                using (var transaction = session.BeginTransaction())
                {
                    try
                    {
                        IList <TSaga> instances = await session.QueryOver <TSaga>()
                                                  .Where(context.Query.FilterExpression)
                                                  .ListAsync <TSaga>()
                                                  .ConfigureAwait(false);

                        if (instances.Count == 0)
                        {
                            var missingSagaPipe = new MissingPipe <T>(session, next);
                            await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
                        }
                        else
                        {
                            await Task.WhenAll(instances.Select(instance => SendToInstance(context, policy, instance, next, session))).ConfigureAwait(false);
                        }

                        // TODO partial failure should not affect them all

                        if (transaction.IsActive)
                        {
                            await transaction.CommitAsync().ConfigureAwait(false);
                        }
                    }
                    catch (SagaException sex)
                    {
                        if (_log.IsErrorEnabled)
                        {
                            _log.Error($"SAGA:{TypeMetadataCache<TSaga>.ShortName} Exception {TypeMetadataCache<T>.ShortName}", sex);
                        }

                        if (transaction.IsActive)
                        {
                            await transaction.RollbackAsync().ConfigureAwait(false);
                        }

                        throw;
                    }
                    catch (Exception ex)
                    {
                        if (_log.IsErrorEnabled)
                        {
                            _log.Error($"SAGA:{TypeMetadataCache<TSaga>.ShortName} Exception {TypeMetadataCache<T>.ShortName}", ex);
                        }

                        if (transaction.IsActive)
                        {
                            await transaction.RollbackAsync().ConfigureAwait(false);
                        }

                        throw new SagaException(ex.Message, typeof(TSaga), typeof(T), Guid.Empty, ex);
                    }
                }
        }
コード例 #15
0
 async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
 {
     using (_container.RequireScope())
     {
         await _repository.Send(context, policy, next).ConfigureAwait(false);
     }
 }
コード例 #16
0
        async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance)
            where T : class
        {
            try
            {
                SagaConsumeContext <TSaga, T> sagaConsumeContext =
                    _documentDbSagaConsumeContextFactory.Create(_client, _databaseName, _collectionName, context, instance, true, _requestOptions);

                sagaConsumeContext.LogUsed();

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    await UpdateDocumentDbSaga(context, instance).ConfigureAwait(false);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
コード例 #17
0
        async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
                                      IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance)
            where T : class
        {
            try
            {
                if (_log.IsDebugEnabled)
                {
                    _log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName, instance.CorrelationId, TypeMetadataCache <T> .ShortName);
                }

                var sagaConsumeContext = new RedisSagaConsumeContext <TSaga, T>(_clientsManager, context, instance);

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    UpdateRedisSaga(instance);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
コード例 #18
0
        async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
                                                     IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            if (!context.CorrelationId.HasValue)
            {
                throw new SagaException("The CorrelationId was not specified", typeof(TSaga), typeof(T));
            }

            Guid sagaId = context.CorrelationId.Value;

            using (DbContext dbContext = _sagaDbContextFactory())
                using (var transaction = dbContext.Database.BeginTransaction(_isolationLevel))
                {
                    bool inserted = false;

                    TSaga instance;
                    if (policy.PreInsertInstance(context, out instance))
                    {
                        inserted = await PreInsertSagaInstance <T>(dbContext, instance, context.CancellationToken).ConfigureAwait(false);
                    }

                    try
                    {
                        if (instance == null)
                        {
                            instance = dbContext.Set <TSaga>().SingleOrDefault(x => x.CorrelationId == sagaId);
                        }
                        if (instance == null)
                        {
                            var missingSagaPipe = new MissingPipe <T>(dbContext, next);

                            await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
                        }
                        else
                        {
                            if (_log.IsDebugEnabled)
                            {
                                _log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName, instance.CorrelationId,
                                                 TypeMetadataCache <T> .ShortName);
                            }

                            var sagaConsumeContext = new EntityFrameworkSagaConsumeContext <TSaga, T>(dbContext, context, instance);

                            await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

//                        if (inserted && !sagaConsumeContext.IsCompleted)
//                            dbContext.Set<TSaga>().Update(instance);
                        }

                        await dbContext.SaveChangesAsync().ConfigureAwait(false);

                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
        }
コード例 #19
0
 public PropertySagaMessageSink(ISagaRepository <TSaga> repository,
                                ISagaPolicy <TSaga, TMessage> policy,
                                Expression <Func <TSaga, TMessage, bool> > selector)
     : base(repository, policy, new PropertySagaLocator <TSaga, TMessage>(repository, policy, selector), GetHandlers)
 {
     Selector = selector;
 }
コード例 #20
0
 public async Task Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next) where T : class
 {
     using (_container.GetNestedContainer())
     {
         await _repository.Send(context, policy, next);
     }
 }
コード例 #21
0
        async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
                                                     IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            if (!context.CorrelationId.HasValue)
            {
                throw new SagaException("The CorrelationId was not specified", typeof(TSaga), typeof(T));
            }

            var sagaId = context.CorrelationId.Value;

            using (var session = _store.DirtyTrackedSession())
            {
                TSaga instance;
                if (policy.PreInsertInstance(context, out instance))
                {
                    PreInsertSagaInstance <T>(session, instance);
                }

                if (instance == null)
                {
                    instance = session.Load <TSaga>(sagaId);
                }

                if (instance == null)
                {
                    var missingSagaPipe = new MissingPipe <T>(session, next);
                    await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
                }
                else
                {
                    await SendToInstance(context, policy, instance, next, session).ConfigureAwait(false);
                }
            }
        }
コード例 #22
0
        async Task SendToInstance <T>(ConsumeContext <T> context,
                                      ISagaPolicy <TSaga, T> policy, TSaga instance,
                                      IPipe <SagaConsumeContext <TSaga, T> > next, IDocumentSession session)
            where T : class
        {
            var sagaConsumeContext = new MartenSagaConsumeContext <TSaga, T>(session, context, instance);

            try
            {
                sagaConsumeContext.LogUsed();

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    await session.SaveChangesAsync().ConfigureAwait(false);
                }
            }
            catch (SagaException sex)
            {
                sagaConsumeContext.LogFault(sex);

                throw;
            }
            catch (Exception ex)
            {
                sagaConsumeContext.LogFault(ex);

                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
コード例 #23
0
 public Task SendQuery <T>(
     SagaQueryConsumeContext <TSaga, T> context, ISagaPolicy <TSaga, T> policy,
     IPipe <SagaConsumeContext <TSaga, T> > next
     ) where T : class
 {
     throw new NotImplementedByDesignException("Redis saga repository does not support queries");
 }
コード例 #24
0
        static string GetPolicy <TComponent, TMessage>(ISagaPolicy <TComponent, TMessage> policy)
            where TComponent : class, ISaga
            where TMessage : class
        {
            string description;
            Type   policyType = policy.GetType().GetGenericTypeDefinition();

            if (policyType == typeof(InitiatingSagaPolicy <,>))
            {
                description = "Initiates New";
            }
            else if (policyType == typeof(ExistingOrIgnoreSagaPolicy <,>))
            {
                description = "Orchestrates Existing";
            }
            else if (policyType == typeof(CreateOrUseExistingSagaPolicy <,>))
            {
                description = "Initiates New Or Orchestrates Existing";
            }
            else
            {
                description = policyType.ToFriendlyName();
            }
            return(description);
        }
コード例 #25
0
 public CorrelatedSagaMessageConnector(IFilter <SagaConsumeContext <TSaga, TMessage> > consumeFilter, ISagaPolicy <TSaga, TMessage> policy,
                                       Func <ConsumeContext <TMessage>, Guid> correlationIdSelector)
 {
     _consumeFilter         = consumeFilter;
     _policy                = policy;
     _correlationIdSelector = correlationIdSelector;
 }
コード例 #26
0
        async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance)
            where T : class
        {
            try
            {
                if (_log.IsDebugEnabled)
                {
                    _log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName, instance.CorrelationId, TypeMetadataCache <T> .ShortName);
                }

                SagaConsumeContext <TSaga, T> sagaConsumeContext =
                    _documentDbSagaConsumeContextFactory.Create(_client, _databaseName, _collectionName, context, instance, true, _requestOptions);

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);

                if (!sagaConsumeContext.IsCompleted)
                {
                    await UpdateDocumentDbSaga(context, instance).ConfigureAwait(false);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
コード例 #27
0
 public CorrelatedSagaFilter(ISagaRepository <TSaga> sagaRepository, ISagaPolicy <TSaga, TMessage> policy,
                             IPipe <SagaConsumeContext <TSaga, TMessage> > messagePipe)
 {
     _sagaRepository = sagaRepository;
     _messagePipe    = messagePipe;
     _policy         = policy;
 }
        public async Task Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next) where T : class
        {
            if (!context.CorrelationId.HasValue)
            {
                throw new SagaException("The CorrelationId was not specified", typeof(TSaga), typeof(T));
            }

            TSaga instance;

            if (policy.PreInsertInstance(context, out instance))
            {
                await PreInsertSagaInstance(context, instance).ConfigureAwait(false);
            }

            if (instance == null)
            {
                instance = await _collection.Find(x => x.CorrelationId == context.CorrelationId).SingleOrDefaultAsync(context.CancellationToken).ConfigureAwait(false);
            }

            if (instance == null)
            {
                var missingSagaPipe = new MissingPipe <TSaga, T>(_collection, next, _mongoDbSagaConsumeContextFactory);

                await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
            }
            else
            {
                await SendToInstance(context, policy, next, instance).ConfigureAwait(false);
            }
        }
コード例 #29
0
        async Task SendToInstance <T>(SagaQueryConsumeContext <TSaga, T> context, ISagaPolicy <TSaga, T> policy, SagaInstance <TSaga> saga,
                                      IPipe <SagaConsumeContext <TSaga, T> > next)
            where T : class
        {
            await saga.MarkInUse(context.CancellationToken).ConfigureAwait(false);

            try
            {
                if (saga.IsRemoved)
                {
                    return;
                }

                if (_log.IsDebugEnabled)
                {
                    _log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName, saga.Instance.CorrelationId, TypeMetadataCache <T> .ShortName);
                }

                SagaConsumeContext <TSaga, T> sagaConsumeContext = new InMemorySagaConsumeContext <TSaga, T>(context, saga.Instance,
                                                                                                             () => Remove(saga, context.CancellationToken));

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);
            }
            finally
            {
                saga.Release();
            }
        }
コード例 #30
0
        public void Send <TMessage>(Expression <Func <T, bool> > filter, ISagaPolicy <T, TMessage> policy, TMessage message, Action <T> consumerAction) where TMessage : class
        {
            ISession session = NHibernateUnitOfWork.Current.Session;

            using (ITransaction transaction = session.BeginTransaction())
            {
                IQueryable <T> existingSagas = session.Linq <T>()
                                               .Where(filter);

                bool foundExistingSagas = SendMessageToExistingSagas(existingSagas, policy, consumerAction, message, session.Delete);

                transaction.Commit();

                if (foundExistingSagas)
                {
                    return;
                }
            }

            using (ITransaction transaction = session.BeginTransaction())
            {
                SendMessageToNewSaga(policy, message, saga =>
                {
                    consumerAction(saga);

                    session.Save(saga);
                }, session.Delete);

                transaction.Commit();
            }
        }