Ejemplo n.º 1
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();
            }
        }
Ejemplo n.º 2
0
        async Task SendToInstance <T>(ConsumeContext <T> context, SqlConnection sqlConnection, ISagaPolicy <TSaga, T> policy, TSaga instance, string tableName,
                                      IPipe <SagaConsumeContext <TSaga, T> > next)
            where T : class
        {
            try
            {
                var sagaConsumeContext = new DapperSagaConsumeContext <TSaga, T>(sqlConnection, context, instance, tableName);

                sagaConsumeContext.LogUsed();

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

                if (!sagaConsumeContext.IsCompleted)
                {
                    await UpdateSagaInstance(sqlConnection, instance).ConfigureAwait(false);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
Ejemplo n.º 3
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;
                }

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

                sagaConsumeContext.LogUsed();

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);
            }
            finally
            {
                saga.Release();
            }
        }
Ejemplo n.º 4
0
        async Task SendToInstance <T>(ITypedDatabase <TSaga> sagas, ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
                                      IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance)
            where T : class
        {
            try
            {
                var sagaConsumeContext = new RedisSagaConsumeContext <TSaga, T>(sagas, context, instance);

                sagaConsumeContext.LogUsed();

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

                if (!sagaConsumeContext.IsCompleted)
                {
                    await UpdateRedisSaga <T>(sagas, instance).ConfigureAwait(false);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
Ejemplo n.º 5
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);
            }
        }
        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);
            }
        }
Ejemplo n.º 7
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);
            }
        }
Ejemplo n.º 8
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);
            }
        }
Ejemplo n.º 9
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);
            }
        }
Ejemplo n.º 10
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;
                    }
                }
        }
Ejemplo n.º 11
0
        async Task SendToInstance <T>(ConsumeContext <T> context, SqlConnection sqlConnection, ISagaPolicy <TSaga, T> policy, TSaga instance, string tableName,
                                      IPipe <SagaConsumeContext <TSaga, T> > next)
            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 DapperSagaConsumeContext <TSaga, T>(sqlConnection, context, instance, tableName);

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

                if (!sagaConsumeContext.IsCompleted)
                {
                    await UpdateSagaInstance(sqlConnection, instance).ConfigureAwait(false);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
Ejemplo n.º 12
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);
            }
        }
Ejemplo n.º 13
0
        public async Task Send(SagaRepositoryQueryContext <TSaga, T> context)
        {
            if (context.Count > 0)
            {
                async Task LoadInstance(Guid correlationId)
                {
                    SagaConsumeContext <TSaga, T> sagaConsumeContext = await context.Load(correlationId).ConfigureAwait(false);

                    if (sagaConsumeContext != null)
                    {
                        sagaConsumeContext.LogUsed();

                        try
                        {
                            await _policy.Existing(sagaConsumeContext, _next).ConfigureAwait(false);

                            if (_policy.IsReadOnly)
                            {
                                await context.Undo(sagaConsumeContext).ConfigureAwait(false);
                            }
                            else
                            {
                                if (sagaConsumeContext.IsCompleted)
                                {
                                    await context.Delete(sagaConsumeContext).ConfigureAwait(false);

                                    sagaConsumeContext.LogRemoved();
                                }
                                else
                                {
                                    await context.Update(sagaConsumeContext).ConfigureAwait(false);
                                }
                            }
                        }
                        finally
                        {
                            switch (sagaConsumeContext)
                            {
                            case IAsyncDisposable asyncDisposable:
                                await asyncDisposable.DisposeAsync().ConfigureAwait(false);

                                break;

                            case IDisposable disposable:
                                disposable.Dispose();
                                break;
                            }
                        }
                    }
                }

                await Task.WhenAll(context.Select(LoadInstance)).ConfigureAwait(false);
            }
            else
            {
                var missingPipe = new MissingSagaPipe <TSaga, T>(context, _next);

                await _policy.Missing(context, missingPipe).ConfigureAwait(false);
            }
        }
Ejemplo n.º 14
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);
            }
        }
        async Task SendToInstance <T>(ITypedDatabase <TSaga> sagas, 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>(sagas, context, instance);

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

                if (!sagaConsumeContext.IsCompleted)
                {
                    await UpdateRedisSaga <T>(sagas, instance).ConfigureAwait(false);
                }
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
Ejemplo n.º 16
0
        public async Task Send(SagaRepositoryContext <TSaga, T> context)
        {
            SagaConsumeContext <TSaga, T> sagaConsumeContext = null;

            if (_policy.PreInsertInstance(context, out var instance))
            {
                sagaConsumeContext = await context.Insert(instance).ConfigureAwait(false);
            }

            sagaConsumeContext ??= await context.Load(_correlationId).ConfigureAwait(false);

            if (sagaConsumeContext != null)
            {
                try
                {
                    sagaConsumeContext.LogUsed();

                    await _policy.Existing(sagaConsumeContext, _next).ConfigureAwait(false);

                    if (_policy.IsReadOnly)
                    {
                        await context.Undo(sagaConsumeContext).ConfigureAwait(false);
                    }
                    else
                    {
                        if (sagaConsumeContext.IsCompleted)
                        {
                            await context.Delete(sagaConsumeContext).ConfigureAwait(false);

                            sagaConsumeContext.LogRemoved();
                        }
                        else
                        {
                            await context.Update(sagaConsumeContext).ConfigureAwait(false);
                        }
                    }
                }
                finally
                {
                    switch (sagaConsumeContext)
                    {
                    case IAsyncDisposable asyncDisposable:
                        await asyncDisposable.DisposeAsync().ConfigureAwait(false);

                        break;

                    case IDisposable disposable:
                        disposable.Dispose();
                        break;
                    }
                }
            }
            else
            {
                await _policy.Missing(context, new MissingSagaPipe <TSaga, T>(context, _next)).ConfigureAwait(false);
            }
        }
Ejemplo n.º 17
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;

            var needToLeaveSagas = true;
            await _sagas.MarkInUse(context.CancellationToken).ConfigureAwait(false);

            try
            {
                SagaInstance <TSaga> saga = _sagas[sagaId];
                if (saga == null)
                {
                    var missingSagaPipe = new MissingPipe <T>(this, next, true);

                    await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);

                    _sagas.Release();
                    needToLeaveSagas = false;
                }
                else
                {
                    await saga.MarkInUse(context.CancellationToken).ConfigureAwait(false);

                    try
                    {
                        _sagas.Release();
                        needToLeaveSagas = false;

                        if (_log.IsDebugEnabled)
                        {
                            _log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName, sagaId, 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();
                    }
                }
            }
            finally
            {
                if (needToLeaveSagas)
                {
                    _sagas.Release();
                }
            }
        }
        async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            if (!context.TryGetPayload(out MessageSessionContext sessionContext))
            {
                throw new SagaException($"The session-based saga repository requires an active message session: {TypeMetadataCache<TSaga>.ShortName}",
                                        typeof(TSaga), typeof(T));
            }

            if (Guid.TryParse(sessionContext.SessionId, out var sessionId))
            {
                context = new CorrelationIdConsumeContextProxy <T>(context, sessionId);
            }

            StartedActivity?activity = LogContext.IfEnabled(OperationName.Saga.Send)?.StartSagaActivity <TSaga, T>(context);

            try
            {
                var saga = await ReadSagaState(sessionContext).ConfigureAwait(false);

                if (saga == null)
                {
                    var missingSagaPipe = new MissingPipe <T>(next, WriteSagaState);

                    await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
                }
                else
                {
                    SagaConsumeContext <TSaga, T> sagaConsumeContext = new MessageSessionSagaConsumeContext <TSaga, T>(context, sessionContext, saga);

                    LogContext.Debug?.Log("SAGA:{SagaType}:{CorrelationId} Used {MessageType}", TypeMetadataCache <TSaga> .ShortName,
                                          context.CorrelationId, TypeMetadataCache <T> .ShortName);

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

                    if (!sagaConsumeContext.IsCompleted)
                    {
                        await WriteSagaState(sessionContext, saga).ConfigureAwait(false);

                        LogContext.Debug?.Log("SAGA:{SagaType}:{CorrelationId} Updated {MessageType}", TypeMetadataCache <TSaga> .ShortName,
                                              context.CorrelationId, TypeMetadataCache <T> .ShortName);
                    }
                }
            }
            finally
            {
                activity?.Stop();
            }
        }
        async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            MessageSessionContext sessionContext;

            if (!context.TryGetPayload(out sessionContext))
            {
                throw new SagaException($"The session-based saga repository requires an active message session: {TypeMetadataCache<TSaga>.ShortName}",
                                        typeof(TSaga), typeof(T));
            }

            Guid sessionId;

            if (Guid.TryParse(sessionContext.SessionId, out sessionId))
            {
                context = new CorrelationIdConsumeContextProxy <T>(context, sessionId);
            }

            var saga = await ReadSagaState(sessionContext).ConfigureAwait(false);

            if (saga == null)
            {
                var missingSagaPipe = new MissingPipe <T>(next, WriteSagaState);

                await policy.Missing(context, missingSagaPipe).ConfigureAwait(false);
            }
            else
            {
                SagaConsumeContext <TSaga, T> sagaConsumeContext = new MessageSessionSagaConsumeContext <TSaga, T>(context, sessionContext, saga);

                if (_log.IsDebugEnabled)
                {
                    _log.DebugFormat("SAGA:{0}:{1} Existing {2}", TypeMetadataCache <TSaga> .ShortName, sessionContext.SessionId, TypeMetadataCache <T> .ShortName);
                }

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

                if (!sagaConsumeContext.IsCompleted)
                {
                    await WriteSagaState(sessionContext, saga).ConfigureAwait(false);

                    if (_log.IsDebugEnabled)
                    {
                        _log.DebugFormat("SAGA:{0}:{1} Updated {2}", TypeMetadataCache <TSaga> .ShortName, sessionContext.SessionId,
                                         TypeMetadataCache <T> .ShortName);
                    }
                }
            }
        }
Ejemplo n.º 20
0
        public async Task Send(SagaRepositoryContext <TSaga, T> context)
        {
            SagaConsumeContext <TSaga, T> sagaConsumeContext = null;

            if (_policy.PreInsertInstance(context, out var instance))
            {
                sagaConsumeContext = await context.Insert(instance).ConfigureAwait(false);
            }

            if (sagaConsumeContext == null)
            {
                sagaConsumeContext = await context.Load(_correlationId).ConfigureAwait(false);
            }

            if (sagaConsumeContext != null)
            {
                try
                {
                    sagaConsumeContext.LogUsed();

                    await _policy.Existing(sagaConsumeContext, _next).ConfigureAwait(false);
                }
                finally
                {
                    switch (sagaConsumeContext)
                    {
                    case IAsyncDisposable asyncDisposable:
                        await asyncDisposable.DisposeAsync().ConfigureAwait(false);

                        break;

                    case IDisposable disposable:
                        disposable.Dispose();
                        break;
                    }
                }
            }
            else
            {
                var missingPipe = new MissingSagaPipe <TSaga, T>(context, _next);

                await _policy.Missing(context, missingPipe).ConfigureAwait(false);
            }
        }
        async Task SendToInstance <T>(SagaQueryConsumeContext <TSaga, T> context, DbContext dbContext, ISagaPolicy <TSaga, T> policy, TSaga instance,
                                      IPipe <SagaConsumeContext <TSaga, T> > next)
            where T : class
        {
            try
            {
                var sagaConsumeContext = new EntityFrameworkSagaConsumeContext <TSaga, T>(dbContext, context, instance);

                sagaConsumeContext.LogUsed();

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
Ejemplo n.º 22
0
        static Task SendToInstance <T>(SagaQueryConsumeContext <TSaga, T> context, ISagaPolicy <TSaga, T> policy, TSaga instance,
                                       IPipe <SagaConsumeContext <TSaga, T> > next, ISession session)
            where T : class
        {
            try
            {
                var sagaConsumeContext = new NHibernateSagaConsumeContext <TSaga, T>(session, context, instance);

                sagaConsumeContext.LogUsed();

                return(policy.Existing(sagaConsumeContext, next));
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
        async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
                                      IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance)
            where T : class
        {
            try
            {
                if (_logger.IsDebugEnabled)
                {
                    _logger.DebugFormat("SAGA: {0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName,
                                        instance.CorrelationId, TypeMetadataCache <T> .ShortName);
                }

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

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

                if (!sagaConsumeContext.IsCompleted)
                {
                    await _connection.SaveEvents(
                        instance.StreamName,
                        instance.GetChanges(),
                        instance.ExpectedVersion,
                        new EventMetadata { CorrelationId = instance.CorrelationId, CausationId = context.MessageId });
                }
            }
            catch (EventStoreSagaConcurrencyException)
            {
                throw;
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
        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 = _mongoDbSagaConsumeContextFactory.Create(_collection, context, instance);

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

                await UpdateMongoDbSaga(context, instance).ConfigureAwait(false);
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
        async Task SendToInstance <T>(SagaQueryConsumeContext <TSaga, T> context, DbContext dbContext, ISagaPolicy <TSaga, T> policy, TSaga instance,
                                      IPipe <SagaConsumeContext <TSaga, T> > next)
            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 EntityFrameworkSagaConsumeContext <TSaga, T>(dbContext, context, instance);

                await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false);
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
Ejemplo n.º 26
0
        static Task SendToInstance <T>(SagaQueryConsumeContext <TSaga, T> context, ISagaPolicy <TSaga, T> policy, TSaga instance,
                                       IPipe <SagaConsumeContext <TSaga, T> > next, ISession 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 NHibernateSagaConsumeContext <TSaga, T>(session, context, instance);

                return(policy.Existing(sagaConsumeContext, next));
            }
            catch (SagaException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex);
            }
        }
        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 dbContext = _sagaDbContextFactory())
                using (var transaction = dbContext.Database.BeginTransaction(_isolationLevel))
                {
                    // Hack for locking row for the duration of the transaction.
                    var tableName = ((IObjectContextAdapter)dbContext).ObjectContext.CreateObjectSet <TSaga>().EntitySet.Name;
                    await dbContext.Database.ExecuteSqlCommandAsync($"select 1 from {tableName} WITH (UPDLOCK, ROWLOCK) WHERE CorrelationId = @p0", sagaId)
                    .ConfigureAwait(false);

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

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

                        transaction.Commit();
                    }
                    catch (DbUpdateException ex)
                    {
                        var baseException = ex.GetBaseException() as SqlException;
                        if (baseException != null && baseException.Number == 1205)
                        {
                            // deadlock, no need to rollback
                        }
                        else
                        {
                            try
                            {
                                transaction.Rollback();
                            }
                            catch (Exception innerException)
                            {
                                if (_log.IsWarnEnabled)
                                {
                                    _log.Warn("The transaction rollback failed", innerException);
                                }
                            }
                        }

                        throw;
                    }
                    catch (Exception)
                    {
                        try
                        {
                            transaction.Rollback();
                        }
                        catch (Exception innerException)
                        {
                            if (_log.IsWarnEnabled)
                            {
                                _log.Warn("The transaction rollback failed", innerException);
                            }
                        }
                        throw;
                    }
                }
        }
Ejemplo n.º 28
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 = _sessionFactory.OpenSession())
                using (var transaction = session.BeginTransaction())
                {
                    var inserted = false;

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

                    try
                    {
                        if (instance == null)
                        {
                            instance = session.Get <TSaga>(sagaId, LockMode.Upgrade);
                        }
                        if (instance == null)
                        {
                            var missingSagaPipe = new MissingPipe <T>(session, 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 NHibernateSagaConsumeContext <TSaga, T>(session, context, instance);

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

                            if (inserted && !sagaConsumeContext.IsCompleted)
                            {
                                session.Update(instance);
                            }
                        }

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

                        if (transaction.IsActive)
                        {
                            transaction.Rollback();
                        }

                        throw;
                    }
                }
        }
        private async Task SendLogic <T>(IDbContextTransaction transaction, DbContext dbContext, ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy,
                                         IPipe <SagaConsumeContext <TSaga, T> > next)
            where T : class
        {
            var sagaId = context.CorrelationId.Value;

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

                if (!inserted)
                {
                    instance = null;            // Reset this back to null if the insert failed. We will use the MissingPipe to create instead
                }
            }

            try
            {
                if (instance == null)
                {
                    IQueryable <TSaga> queryable = QuerySagas(dbContext);

                    // Query with a row Lock instead using FromSql. Still a single trip to the DB (unlike EF6, which has to make one dummy call to row lock)
                    var rowLockQuery = _rawSqlLockStatements?.GetRowLockStatement <TSaga>(dbContext);
                    if (rowLockQuery != null)
                    {
                        instance = await queryable.FromSql(rowLockQuery, new object[] { sagaId }).SingleOrDefaultAsync(context.CancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        instance = await queryable.SingleOrDefaultAsync(x => x.CorrelationId == sagaId, context.CancellationToken).ConfigureAwait(false);
                    }
                }

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

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

                transaction.Commit();
            }
            catch (DbUpdateConcurrencyException)
            {
                try
                {
                    transaction.Rollback();
                }
                catch (Exception innerException)
                {
                    if (_log.IsWarnEnabled)
                    {
                        _log.Warn("The transaction rollback failed", innerException);
                    }
                }

                throw;
            }
            catch (DbUpdateException ex)
            {
                if (IsDeadlockException(ex))
                {
                    // deadlock, no need to rollback
                }
                else
                {
                    if (_log.IsErrorEnabled)
                    {
                        _log.Error($"SAGA:{TypeMetadataCache<TSaga>.ShortName} Exception {TypeMetadataCache<T>.ShortName}", ex);
                    }

                    try
                    {
                        transaction.Rollback();
                    }
                    catch (Exception innerException)
                    {
                        if (_log.IsWarnEnabled)
                        {
                            _log.Warn("The transaction rollback failed", innerException);
                        }
                    }
                }

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

                try
                {
                    transaction.Rollback();
                }
                catch (Exception innerException)
                {
                    if (_log.IsWarnEnabled)
                    {
                        _log.Warn("The transaction rollback failed", innerException);
                    }
                }

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

            var dbContext = _sagaDbContextFactory.CreateScoped(context);

            try
            {
                using (var transaction = dbContext.Database.BeginTransaction(_isolationLevel))
                {
                    if (policy.PreInsertInstance(context, out var instance))
                    {
                        var inserted = await PreInsertSagaInstance <T>(dbContext, instance, context.CancellationToken).ConfigureAwait(false);

                        if (!inserted)
                        {
                            instance = null;            // Reset this back to null if the insert failed. We will use the MissingPipe to create instead
                        }
                    }

                    try
                    {
                        if (instance == null)
                        {
                            // Only perform this additional DB Call for pessimistic concurrency
                            if (_rawSqlLockStatements != null)
                            {
                                var rowLockQuery = _rawSqlLockStatements.GetRowLockStatement <TSaga>(dbContext);
                                await dbContext.Database.ExecuteSqlCommandAsync(rowLockQuery, context.CancellationToken, sagaId).ConfigureAwait(false);
                            }

                            instance = await QuerySagas(dbContext)
                                       .SingleOrDefaultAsync(x => x.CorrelationId == sagaId, context.CancellationToken)
                                       .ConfigureAwait(false);
                        }

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

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

                        transaction.Commit();
                    }
                    catch (DbUpdateConcurrencyException)
                    {
                        try
                        {
                            transaction.Rollback();
                        }
                        catch (Exception innerException)
                        {
                            if (_log.IsWarnEnabled)
                            {
                                _log.Warn("The transaction rollback failed", innerException);
                            }
                        }

                        throw;
                    }
                    catch (DbUpdateException ex)
                    {
                        if (IsDeadlockException(ex))
                        {
                            // deadlock, no need to rollback
                        }
                        else
                        {
                            if (_log.IsErrorEnabled)
                            {
                                _log.Error($"SAGA:{TypeMetadataCache<TSaga>.ShortName} Exception {TypeMetadataCache<T>.ShortName}", ex);
                            }

                            try
                            {
                                transaction.Rollback();
                            }
                            catch (Exception innerException)
                            {
                                if (_log.IsWarnEnabled)
                                {
                                    _log.Warn("The transaction rollback failed", innerException);
                                }
                            }
                        }

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

                        try
                        {
                            transaction.Rollback();
                        }
                        catch (Exception innerException)
                        {
                            if (_log.IsWarnEnabled)
                            {
                                _log.Warn("The transaction rollback failed", innerException);
                            }
                        }

                        throw;
                    }
                }
            }
            finally
            {
                _sagaDbContextFactory.Release(dbContext);
            }
        }