/// <summary> /// Send Transaction with optimistic lock /// Send with multiple thread /// </summary> /// <param name="repoQuery"></param> /// <param name="rpcClass"></param> /// <param name="privateKey"></param> /// <typeparam name="TBlockchainTransaction"></typeparam> /// <returns></returns> public virtual async Task <ReturnObject> SendTransactionAsync <TBlockchainTransaction>( IRepositoryBlockchainTransaction <TBlockchainTransaction> repoQuery, IBlockchainRpc rpcClass, string privateKey = "") where TBlockchainTransaction : BlockchainTransaction { /* * 1. Query Transaction Withdraw pending * 2. Update Processing = 1, version = version + 1 * 3. Commit Transaction * 4. Call RPC send transaction * 5. Update Transaction Status */ // find transaction pending // var pendingTransaction = repoQuery.FindTransactionPending(); var pendingTransaction = repoQuery.FindRowPending(); if (pendingTransaction?.Id == null) { //if (!CacheHelper.HaveKey("cache")) //{ // long numberOfTicks = (DateTime.Now.Ticks - startTime); // TimeSpan ts = TimeSpan.FromTicks(numberOfTicks); // double minutesFromTs = ts.TotalMinutes; // CacheHelper.SetCacheString("cache", minutesFromTs.ToString()); //} //Console.WriteLine("END TIME " + CacheHelper.GetCacheString("cache")); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Not found Transaction" }); } if (DbConnection.State != ConnectionState.Open) { //Console.WriteLine(DbConnection.State); DbConnection.Open(); } //begin first transaction var transactionScope = DbConnection.BeginTransaction(); try { //lock transaction for process var resultLock = await repoQuery.LockForProcess(pendingTransaction); if (resultLock.Status == Status.STATUS_ERROR) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Cannot Lock For Process" }); } //commit transaction transactionScope.Commit(); } catch (Exception e) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = e.ToString() }); } //Update Version to Model pendingTransaction.Version += 1; //start send and update var transactionDbSend = DbConnection.BeginTransaction(); try { //Call RPC Transaction //TODO EDIT RPC Class var sendTransaction = await rpcClass.SendTransactionAsync(pendingTransaction); pendingTransaction.Status = sendTransaction.Status; pendingTransaction.IsProcessing = 0; // pendingTransaction.UpdatedAt = (int) CommonHelper.GetUnixTimestamp(); // set in SafeUpdate pendingTransaction.Hash = sendTransaction.Data; //create database email when send success if (sendTransaction.Status == Status.STATUS_COMPLETED) { var email = GetEmailByTransaction(pendingTransaction); if (email != null) { // await CreateDataEmail("Notify send " + pendingTransaction.NetworkName(), // email, pendingTransaction.Amount, // Constants.TEMPLATE_EMAIL_SENT, pendingTransaction.NetworkName(),Constants.TYPE_SEND); await SendMailBusiness.SendMailBusiness.CreateDataEmail("Notify send " + pendingTransaction.NetworkName(), email, pendingTransaction.Amount, pendingTransaction.Id, EmailTemplate.Sent, pendingTransaction.NetworkName(), VakapayRepositoryFactory, false); } } var result = await repoQuery.SafeUpdate(pendingTransaction); if (result.Status == Status.STATUS_ERROR) { transactionDbSend.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = "Cannot Save Transaction Status" }); } transactionDbSend.Commit(); return(new ReturnObject { Status = sendTransaction.Status, Message = sendTransaction.Message, Data = sendTransaction.Data }); } catch (Exception e) { //release lock transactionDbSend.Rollback(); var resultRelease = repoQuery.ReleaseLock(pendingTransaction); Console.WriteLine(JsonHelper.SerializeObject(resultRelease)); throw e; } }
/// <summary> /// Send Transaction with optimistic lock /// Send with multiple thread /// </summary> /// <param name="repoQuery"></param> /// <param name="rpcClass"></param> /// <param name="privateKey"></param> /// <typeparam name="TBlockchainTransaction"></typeparam> /// <returns></returns> public virtual async Task <ReturnObject> SendTransactionAsync <TBlockchainTransaction>( IRepositoryBlockchainTransaction <TBlockchainTransaction> repoQuery, IBlockchainRpc rpcClass, string privateKey = "") where TBlockchainTransaction : BlockchainTransaction { /* * 1. Query Transaction Withdraw pending * 2. Update Processing = 1, version = version + 1 * 3. Commit Transaction * 4. Call RPC send transaction * 5. Update Transaction Status */ var pendingTransaction = repoQuery.FindRowPending(); if (pendingTransaction?.Id == null) { //Console.WriteLine("END TIME " + CacheHelper.GetCacheString("cache")); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Not found Transaction" }); } if (DbConnection.State != ConnectionState.Open) { //Console.WriteLine(DbConnection.State); DbConnection.Open(); } //begin first transaction var transactionScope = DbConnection.BeginTransaction(); try { //lock transaction for process var resultLock = await repoQuery.LockForProcess(pendingTransaction); if (resultLock.Status == Status.STATUS_ERROR) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_SUCCESS, Message = "Cannot Lock For Process" }); } //commit transaction transactionScope.Commit(); } catch (Exception e) { transactionScope.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = e.ToString() }); } //Update Version to Model pendingTransaction.Version += 1; //start send and update var transactionDbSend = DbConnection.BeginTransaction(); try { //Call RPC Transaction //TODO EDIT RPC Class var sendTransaction = await rpcClass.SendTransactionAsync1(pendingTransaction); pendingTransaction.Status = sendTransaction.Status; pendingTransaction.IsProcessing = 0; pendingTransaction.Hash = sendTransaction.Data; //create database email when send success if (sendTransaction.Status == Status.STATUS_COMPLETED) { // var email = GetEmailByTransaction(pendingTransaction); // if (email != null) // { // // await SendMailBusiness.SendMailBusiness.CreateDataEmail( // "Notify send " + pendingTransaction.NetworkName(), // email, pendingTransaction.Amount, pendingTransaction.Id, // EmailTemplate.Sent, pendingTransaction.NetworkName(), SmartContractRepositoryFactory, // false); // } } var result = await repoQuery.SafeUpdate(pendingTransaction); if (result.Status == Status.STATUS_ERROR) { transactionDbSend.Rollback(); return(new ReturnObject { Status = Status.STATUS_ERROR, Message = "Cannot Save Transaction Status" }); } transactionDbSend.Commit(); return(new ReturnObject { Status = sendTransaction.Status, Message = sendTransaction.Message, Data = sendTransaction.Data }); } catch (Exception e) { //release lock Console.WriteLine(e.Message); transactionDbSend.Rollback(); var resultRelease = repoQuery.ReleaseLock(pendingTransaction); Console.WriteLine(JsonHelper.SerializeObject(resultRelease)); throw e; } }