public override void Dispose(IIocResolver iocResolver) { //foreach (var dtx in DbContexts) //{ // var CurrentTransaction = dataBaseTransactions.FirstOrDefault(t => t.dbContext == dtx); // if (CurrentTransaction != null && !CurrentTransaction.isCommit && CurrentTransaction.Transaction != null) // { // CurrentTransaction.Transaction.Rollback(); // CurrentTransaction.Transaction.Dispose(); // dataBaseTransactions.Remove(CurrentTransaction); // } //} foreach (var activeTransaction in ActiveTransactions.Values) { activeTransaction.DbContextTransaction.Dispose(); foreach (var attendedDbContext in activeTransaction.AttendedDbContexts) { iocResolver.Release(attendedDbContext); } iocResolver.Release(activeTransaction.StarterDbContext); } ActiveTransactions.Clear(); base.Dispose(iocResolver); }
public async Task StartDistributedTransaction(string transactionName, IEnumerable <string> transactionActors) { while (!ReliableDictionariesInitialized) { await Task.Delay(1000); } if (await ActiveTransactions.ContainsKeyAsync(transactionName)) { string warnMessage = $"{baseLogString} StartDistributedUpdate => Transaction with name '{transactionName}' has already been stated."; Logger.LogWarning(warnMessage); return; } var actorsHashSet = new HashSet <string>(transactionActors); await ActiveTransactions.SetAsync(transactionName, actorsHashSet); await TransactionEnlistmentLedger.SetAsync(transactionName, new HashSet <string>()); var actorsSb = new StringBuilder(); foreach (var actor in actorsHashSet) { actorsSb.Append($"'{actor}', "); } Logger.LogInformation($"{baseLogString} StartDistributedUpdate => Distributed transaction '{transactionName}' SUCCESSFULLY started. Waiting for transaction actors [{actorsSb}] to enlist."); }
private static async Task CreateActiveTransactionsDocIfNotExists(ActiveTransactions activeTransactionsDoc) { var client = new DocumentClient(new Uri(Endpoint), AuthKey); Uri collectionLink = UriFactory.CreateDocumentCollectionUri(DbName, CollectionName); bool needToCreate = false; try { await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DbName, CollectionName, activeTransactionsDoc.Id.ToString())); } catch (DocumentClientException de) { if (de.StatusCode != HttpStatusCode.NotFound) { throw; } else { needToCreate = true; } } if (needToCreate) { await client.CreateDocumentAsync(collectionLink, activeTransactionsDoc); } }
public virtual void Dispose() { foreach (var activeTransaction in ActiveTransactions.Values) { //if (activeTransaction.AttendedDbContexts != null && activeTransaction.AttendedDbContexts.Count > 0) //{ // foreach (var attendedDbContext in activeTransaction.AttendedDbContexts) // { // attendedDbContext.Dispose(); // } //} if (activeTransaction.DbContextTransaction != null) { activeTransaction.DbContextTransaction.Dispose(); } if (activeTransaction.DbContext.Database.CurrentTransaction != null) { activeTransaction.DbContext.Database.CurrentTransaction.Dispose(); } } ActiveTransactions.Clear(); if (CurrentTransaction != null) { CurrentTransaction.Dispose(); CurrentTransaction = null; } }
public ISession GetOrCreateSession <TSessionContext>(Type type = null) where TSessionContext : ISessionContext { // var context = Ioc.Create(typeof(TSessionContext)); var _context = Ioc.Create <ISessionContext>(typeof(TSessionContext)); ISessionFactory sessionFactory = _sessionFactoryProvider.GetSessionFactory(_context.Name); string sessionKey = _context.Name + "#"; string connectionString = _context.GetConnectionString(); if (!ActiveSessions.TryGetValue(sessionKey, out ISession session)) { if (Options.IsTransactional == true) { ActiveTransactionInfo activeTransactionInfo = ActiveTransactions.GetOrDefault(connectionString); if (activeTransactionInfo == null) { session = DbConnection != null ? sessionFactory.WithOptions().Connection(DbConnection).OpenSession() : sessionFactory.OpenSession(); ITransaction transaction = Options.IsolationLevel.HasValue ? session.BeginTransaction(Options.IsolationLevel.Value.ToSystemDataIsolationLevel()) : session.BeginTransaction(); activeTransactionInfo = new ActiveTransactionInfo(transaction, session.Connection, session); ActiveTransactions[connectionString] = activeTransactionInfo; } else { session = activeTransactionInfo.StarterSession; activeTransactionInfo.AttendedSessions.Add(session); } } else { session = DbConnection != null ? sessionFactory.OpenSessionWithConnection(DbConnection) : sessionFactory.OpenSession(); } ActiveSessions[sessionKey] = session; } var filters = _context.Filters().ToList(); foreach (var filter in filters) { var name = filter.Name(); var parameters = filter.Parameters(); var _filter = session.EnableFilter(name); foreach (var parameter in parameters) { _filter.SetParameter(parameter.Key, parameter.Value); } } return(session); }
public override DbContext CreateDbContext <TDbContext>(string connectionString, IDbContextResolver dbContextResolver, string moduleName) { //var dtx = base.CreateDbContext<TDbContext>(connectionString, dbContextResolver, moduleName); //var currentIsolation = (IsolationLevel)SafeConvert.ToEnum(typeof(IsolationLevel), (object)Options.IsolationLevel, IsolationLevel.ReadUncommitted); //if (Options.IsTransactional == true && isBeginTransaction) //{ // dataBaseTransactions.Add(new DataBaseTransaction() // { // Transaction = dtx.Database.BeginTransaction(currentIsolation), // dbContext = dtx, // isCommit = false // }); //} //return dtx; DbContext dbContext; var activeTransaction = ActiveTransactions.GetOrDefault(connectionString); if (activeTransaction == null) { dbContext = dbContextResolver.Resolve <TDbContext>(connectionString, moduleName); var dbtransaction = dbContext.Database.BeginTransaction((Options.IsolationLevel ?? IsolationLevel.ReadCommitted).ToSystemDataIsolationLevel()); activeTransaction = new ActiveTransactionInfo(dbtransaction, dbContext); ActiveTransactions[connectionString] = activeTransaction; } else { dbContext = dbContextResolver.Resolve <TDbContext>( activeTransaction.DbContextTransaction.GetDbTransaction().Connection, moduleName, true ); if (dbContext.HasRelationalTransactionManager()) { dbContext.Database.UseTransaction(activeTransaction.DbContextTransaction.GetDbTransaction()); } else { dbContext.Database.BeginTransaction(); } activeTransaction.AttendedDbContexts.Add(dbContext); } return(dbContext); }
public ISession GetOrCreateSession <TSessionContext>() where TSessionContext : StoveSessionContext { ISessionFactory sessionFactory = _sessionFactoryProvider.GetSessionFactory <TSessionContext>(); var connectionStringResolveArgs = new ConnectionStringResolveArgs(); connectionStringResolveArgs["SessionContextType"] = typeof(TSessionContext); string connectionString = ResolveConnectionString(connectionStringResolveArgs); string sessionKey = typeof(TSessionContext).FullName + "#" + connectionString; if (!ActiveSessions.TryGetValue(sessionKey, out ISession session)) { if (Options.IsTransactional == true) { ActiveTransactionInfo activeTransactionInfo = ActiveTransactions.GetOrDefault(connectionString); if (activeTransactionInfo == null) { session = DbConnection != null ? sessionFactory.WithOptions().Connection(DbConnection).OpenSession() : sessionFactory.OpenSession(); ITransaction transaction = Options.IsolationLevel.HasValue ? session.BeginTransaction(Options.IsolationLevel.Value.ToSystemDataIsolationLevel()) : session.BeginTransaction(); activeTransactionInfo = new ActiveTransactionInfo(transaction, session.Connection, session); ActiveTransactions[connectionString] = activeTransactionInfo; } else { session = activeTransactionInfo.StarterSession; activeTransactionInfo.AttendedSessions.Add(session); } } else { session = DbConnection != null ? sessionFactory.OpenSessionWithConnection(DbConnection) : sessionFactory.OpenSession(); } ActiveSessions[sessionKey] = session; } return(session); }
private static async Task ResetActiveTransactionsDocIfNotExists() { var client = new DocumentClient(new Uri(Endpoint), AuthKey); Uri collectionLink = UriFactory.CreateDocumentUri(DbName, CollectionName, activeTransactionsDocId.ToString()); ActiveTransactions activeTransactionsDoc = new ActiveTransactions { Id = activeTransactionsDocId, Transactions = new List <string>() }; try { await client.ReplaceDocumentAsync(collectionLink, activeTransactionsDoc); } catch (DocumentClientException de) { throw; } }
private async Task InvokeRollbackOnActors(string transactionName) { var enumerableActiveTransactions = await ActiveTransactions.GetEnumerableDictionaryAsync(); if (!enumerableActiveTransactions.ContainsKey(transactionName)) { string errorMessage = $"{baseLogString} InvokeRollbackOnActors => transaction '{transactionName}' not found in '{ReliableDictionaryNames.ActiveTransactions}'."; Logger.LogError(errorMessage); throw new Exception(errorMessage); } var result = await TransactionEnlistmentLedger.TryGetValueAsync(transactionName); if (!result.HasValue) { string errorMessage = $"{baseLogString} InvokeRollbackOnActors => Transaction '{transactionName}' not found in '{ReliableDictionaryNames.TransactionEnlistmentLedger}'."; Logger.LogError(errorMessage); throw new Exception(errorMessage); } var transactionLedger = result.Value; List <Task> tasks = new List <Task>(); foreach (var transactionActorName in transactionLedger) { if (enumerableActiveTransactions[transactionName].Contains(transactionActorName)) { var task = Task.Run(async() => { ITransactionActorContract transactionActorClient = TransactionActorClient.CreateClient(transactionActorName); await transactionActorClient.Rollback(); Logger.LogInformation($"{baseLogString} InvokeRollbackOnActors => Rollback invoked on Transaction actor: {transactionActorName}."); }); tasks.Add(task); } } Task.WaitAll(tasks.ToArray()); Logger.LogInformation($"{baseLogString} InvokeRollbackOnActors => Rollback SUCCESSFULLY invoked on all transaction actors."); }
/// <summary> /// Rollbacks transaction and closes database connection. /// </summary> protected override void DisposeUow() { foreach (ActiveTransactionInfo activeTransaction in ActiveTransactions.Values) { foreach (ISession session in activeTransaction.AttendedSessions) { session.Dispose(); } activeTransaction.Transaction.Dispose(); activeTransaction.StarterSession.Dispose(); } foreach (ISession activeSession in ActiveSessions.Values) { activeSession.Dispose(); } ActiveSessions.Clear(); ActiveTransactions.Clear(); }
public async Task <bool> Enlist(string transactionName, string transactionActorName) { while (!ReliableDictionariesInitialized) { await Task.Delay(1000); } var enumerableActiveTransactions = await ActiveTransactions.GetEnumerableDictionaryAsync(); if (!enumerableActiveTransactions.ContainsKey(transactionName)) { string errorMessage = $"{baseLogString} Enlist => transaction '{transactionName}' not found in '{ReliableDictionaryNames.ActiveTransactions}'."; Logger.LogError(errorMessage); throw new Exception(errorMessage); } var result = await TransactionEnlistmentLedger.TryGetValueAsync(transactionName); if (!result.HasValue) { string errorMessage = $"{baseLogString} Enlist => Transaction '{transactionName}' not found in '{ReliableDictionaryNames.TransactionEnlistmentLedger}'."; Logger.LogError(errorMessage); throw new Exception(errorMessage); } var transactionLedger = result.Value; if (!enumerableActiveTransactions[transactionName].Contains(transactionActorName)) { string errorMessage = $"{baseLogString} InvokePreparationOnActors => Transaction '{transactionName}' not found in '{ReliableDictionaryNames.TransactionEnlistmentLedger}'."; Logger.LogError(errorMessage); return(false); } transactionLedger.Add(transactionActorName); await TransactionEnlistmentLedger.SetAsync(transactionName, transactionLedger); return(true); }
// This console application accomplishes the following: // 1. Creates and inserts a document designated for keeping track of the list of currently active transaction ids. // 2. Generates a GUID (let's call this tId0 for the new transaction and adds this to the document created in step 1. // 3. Invokes the bulk import stored procedure. Upon insertion of each document, a new property TransactionId with value = tId0 is added to associate each processed document // with the current active transaction. // 4. If the bulk import stored procedure completes successfully, remove tId0 from the document created in step 1. // 5. If the bulk import stored procedure fails to complete, clean up the processed documents with TransactionId = tId0. Do this by invoking the bulk delete stored procedure. // Remove tId0 from teh document created in step 1. static void Main(string[] args) { Console.WriteLine("Using {0}, {1}, {2}", Endpoint, DbName, CollectionName); activeTransactionsDocId = Guid.NewGuid(); ActiveTransactions activeTransactionsDoc = new ActiveTransactions { Id = activeTransactionsDocId, Transactions = new List <string>() }; // Generate the document that keeps track of active transactions if it does not already exist. CreateActiveTransactionsDocIfNotExists(activeTransactionsDoc).Wait(); // Add a new guid to the list of active transactions for the current transaction. AddActiveTransaction().Wait(); // Invoke bulk import sproc, adding new property TransactionId with value = current active transaction to each imported document. InvokeBulkImportSproc().Wait(); // If bulk import succeeded (or if bulk delete completed successfully), remove id of the current transaction from the active transactions document. RemoveActiveTransaction().Wait(); }
// This console application accomplishes the following: // 1. Creates and inserts a document designated for keeping track of the list of currently active transaction ids. // 2. Generates a GUID (let's call this tId0 for the new transaction and adds this to the document created in step 1. // 3. Invokes the bulk import stored procedure. Upon insertion of each document, a new property TransactionId with value = tId0 is added to associate each processed document // with the current active transaction. // 4. If the bulk import stored procedure completes successfully, remove tId0 from the document created in step 1. // 5. If the bulk import stored procedure fails to complete, clean up the processed documents with TransactionId = tId0. Do this by invoking the bulk delete stored procedure. // Remove tId0 from teh document created in step 1. static void Main(string[] args) { Console.WriteLine("Using {0}, {1}, {2}", Endpoint, DbName, CollectionName); activeTransactionsDocId = Guid.NewGuid(); ActiveTransactions activeTransactionsDoc = new ActiveTransactions { Id = activeTransactionsDocId, Transactions = new List<string>() }; // Generate the document that keeps track of active transactions if it does not already exist. CreateActiveTransactionsDocIfNotExists(activeTransactionsDoc).Wait(); // Add a new guid to the list of active transactions for the current transaction. AddActiveTransaction().Wait(); // Invoke bulk import sproc, adding new property TransactionId with value = current active transaction to each imported document. InvokeBulkImportSproc().Wait(); // If bulk import succeeded (or if bulk delete completed successfully), remove id of the current transaction from the active transactions document. RemoveActiveTransaction().Wait(); }
public async Task <bool> FinishDistributedTransaction(string transactionName, bool success) { while (!ReliableDictionariesInitialized) { await Task.Delay(1000); } bool result; try { if (success) { bool prepareSuccess = false; int retryCount = 30; while (--retryCount > 0) { try { prepareSuccess = await InvokePreparationOnActors(transactionName); break; } catch (NotAllActorsEnlistedException) { prepareSuccess = false; await Task.Delay(2000); continue; } catch (Exception e) { prepareSuccess = false; string errorMessage = $"{baseLogString} FinishDistributedTransaction => Exception in InvokePreparationOnActors: {e.Message}"; Logger.LogError(errorMessage); break; } } if (prepareSuccess) { await InvokeCommitOnActors(transactionName); Logger.LogInformation($"{baseLogString} FinishDistributedUpdate => Distributed transaction finsihed SUCCESSFULLY."); } else { await InvokeRollbackOnActors(transactionName); Logger.LogInformation($"{baseLogString} FinishDistributedUpdate => Distributed transaction finsihed UNSUCCESSFULLY."); } result = prepareSuccess; } else { Logger.LogInformation($"{baseLogString} FinishDistributedUpdate => Distributed transaction finsihed UNSUCCESSFULLY."); result = false; } } catch (Exception e) { Logger.LogError($"{baseLogString} FinishDistributedUpdate => Exception: {e.Message}"); result = false; } finally { await ActiveTransactions.TryRemoveAsync(transactionName); await TransactionEnlistmentLedger.TryRemoveAsync(transactionName); } return(result); }
protected virtual IReadOnlyList <ITransaction> GetAllActiveTransactions() { return(ActiveTransactions.Select(x => x.Value.Transaction).ToList()); }
private static async Task ResetActiveTransactionsDocIfNotExists() { var client = new DocumentClient(new Uri(Endpoint), AuthKey); Uri collectionLink = UriFactory.CreateDocumentUri(DbName, CollectionName, activeTransactionsDocId.ToString()); ActiveTransactions activeTransactionsDoc = new ActiveTransactions { Id = activeTransactionsDocId, Transactions = new List<string>() }; try { await client.ReplaceDocumentAsync(collectionLink, activeTransactionsDoc); } catch (DocumentClientException de) { throw; } }
private static async Task CreateActiveTransactionsDocIfNotExists(ActiveTransactions activeTransactionsDoc) { var client = new DocumentClient(new Uri(Endpoint), AuthKey); Uri collectionLink = UriFactory.CreateDocumentCollectionUri(DbName, CollectionName); bool needToCreate = false; try { await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DbName, CollectionName, activeTransactionsDoc.Id.ToString())); } catch (DocumentClientException de) { if (de.StatusCode != HttpStatusCode.NotFound) { throw; } else { needToCreate = true; } } if (needToCreate) { await client.CreateDocumentAsync(collectionLink, activeTransactionsDoc); } }
private async Task <bool> InvokePreparationOnActors(string transactionName) { bool success; var enumerableActiveTransactions = await ActiveTransactions.GetEnumerableDictionaryAsync(); if (!enumerableActiveTransactions.ContainsKey(transactionName)) { string errorMessage = $"{baseLogString} InvokePreparationOnActors => transaction '{transactionName}' not found in '{ReliableDictionaryNames.ActiveTransactions}'."; Logger.LogError(errorMessage); throw new Exception(errorMessage); } var result = await TransactionEnlistmentLedger.TryGetValueAsync(transactionName); if (!result.HasValue) { string errorMessage = $"{baseLogString} InvokePreparationOnActors => Transaction '{transactionName}' not found in '{ReliableDictionaryNames.TransactionEnlistmentLedger}'."; Logger.LogError(errorMessage); throw new Exception(errorMessage); } var transactionLedger = result.Value; if (!enumerableActiveTransactions[transactionName].SetEquals(transactionLedger)) { string errorMessage = $"{baseLogString} InvokePreparationOnActors => not all actors have enlisted for the transaction '{transactionName}'."; Logger.LogError(errorMessage); throw new NotAllActorsEnlistedException(errorMessage); } List <Task <Tuple <string, bool> > > tasks = new List <Task <Tuple <string, bool> > >(); foreach (var transactionActorName in transactionLedger) { var task = Task.Run(async() => { ITransactionActorContract transactionActorClient = TransactionActorClient.CreateClient(transactionActorName); var prepareSuccess = await transactionActorClient.Prepare(); Logger.LogInformation($"{baseLogString} InvokePreparationOnActors => Prepare invoked on Transaction actor: {transactionActorName}, Success: {prepareSuccess}."); return(new Tuple <string, bool>(transactionActorName, prepareSuccess)); }); tasks.Add(task); } var taskResults = await Task.WhenAll(tasks); success = true; foreach (var taskResult in taskResults) { var actorUri = taskResult.Item1; var prepareSuccess = taskResult.Item2; success = success && prepareSuccess; if (success) { Logger.LogInformation($"{baseLogString} InvokePreparationOnActors => Preparation on Transaction actor: {actorUri} finsihed SUCCESSFULLY."); } else { Logger.LogInformation($"{baseLogString} InvokePreparationOnActors => Preparation on Transaction actor: {actorUri} finsihed UNSUCCESSFULLY."); break; } } return(success); }
protected internal virtual void TerminateTransactionsForValidUser(string username) { KernelTransaction currentTx = CurrentTx; ActiveTransactions.Where(tx => tx.subject().hasUsername(username) && !tx.isUnderlyingTransaction(currentTx)).ForEach(tx => tx.markForTermination(Org.Neo4j.Kernel.Api.Exceptions.Status_Transaction.Terminated)); }