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