Lesson Learned #180: Creating a retry-logic for TSQL command execution.

Published Dec 28 2021 06:59 AM 1,377 Views

As you know, one of the recommendations that we have in Azure SQL Database is to have a connection retry-logic, however, I would like to share with you other recommendation for command execution.

 

I developed the following piece of code that receives, four parameters. 

  • ConnectionString: Contains the connection string.
  • QueryText: Contains the query to execute.
  • retryIntervalSeconds: how much time the command timeout will be at the begining.
  • HowManyRetries: how many time the execution will be retried until fails.

 

Basically, as you could see in the example source code the operation will be:

 

  • 1) Connect to the DB. This function has a connection retry-logic that we shared in previous article.
  • 2) Try to execute the query (in this example will be NonQuery type) using the CommandTimeout specified in the parameter value called retryIntervalSeconds. 
  • 3) If the execution failed, the next command execution timeout will be multiple by 2.5. It and will be executed again until success or fails after retrying specified in the parameter value called HowManyRetries. 
  • 4) Also, I added an useful information, about how much the execution took, connection time, execution time and ConnectionID, etc..

 

Source code example:

 

 

public bool RunQueryWithRetriesNonQuery(string ConnectionString, 
                                                string QueryText,  
                                                int retryIntervalSeconds = 5, 
                                                int HowManyRetries = 5)
        {
            bool returnBool = false;
            int totalNrRows = 0;
            Stopwatch stopWatchWholeProcess = new Stopwatch();
            Stopwatch stopWatchRealTime = new Stopwatch();
            ClsRetryLogic oClsRetry = new ClsRetryLogic();
            C.SqlConnection SqlConnection = new C.SqlConnection();
            C.SqlCommand SqlCommand = new C.SqlCommand(QueryText, SqlConnection);

            SqlConnection.StatisticsEnabled = true;

            stopWatchWholeProcess.Start();

                for (int tries = 1; tries <= HowManyRetries; tries++)
                {
                 try
                 {
                    if (oClsRetry.ConnectDBWithRetry(ConnectionString, SqlConnection, false))
                    {

                        if (tries > 1) { retryIntervalSeconds = Convert.ToInt32(retryIntervalSeconds * 2.5); }

                        SqlCommand.CommandTimeout = retryIntervalSeconds;

                        Console.WriteLine("Executing the query {0} - Attempt Nr.:{1} - CommandTimeout: {2} - ConnectionID:{3}", QueryText, tries, SqlCommand.CommandTimeout, SqlConnection.ClientConnectionId);
                        Console.WriteLine();
                        stopWatchRealTime.Start();
                        totalNrRows = (int)SqlCommand.ExecuteNonQuery();
                        stopWatchRealTime.Stop();
                        stopWatchWholeProcess.Stop();

                        TimeSpan ts = stopWatchWholeProcess.Elapsed;
                        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                            ts.Hours, ts.Minutes, ts.Seconds,
                            ts.Milliseconds / 10);

                        ts = stopWatchRealTime.Elapsed;
                        string elapsedTimeRealTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                            ts.Hours, ts.Minutes, ts.Seconds,
                            ts.Milliseconds / 10);

                        Console.WriteLine("Query Executed Text:{0} - Total ElapsedTime:{1} - Real Time:{5} - Rows:{2} - Tries:{3} - CommandTimeout:{4}",QueryText, elapsedTime, totalNrRows, tries, SqlCommand.CommandTimeout, elapsedTimeRealTime);
                        Console.WriteLine();

                        IDictionary currentStatistics = SqlConnection.RetrieveStatistics();

                        Console.WriteLine("---- BytesReceived: {0}",(long)currentStatistics["BytesReceived"]);
                        Console.WriteLine("---- BytesSent: {0}", (long)currentStatistics["BytesSent"]);
                        Console.WriteLine("---- ExecutionTime: {0}", (long)currentStatistics["ExecutionTime"]);
                        Console.WriteLine("---- ConnectionTime: {0}", (long)currentStatistics["ConnectionTime"] );

                        returnBool = true;
                        SqlConnection.Close();
                        break;
                    }
                    else
                    {
                        Console.WriteLine("Connectivity Error..");
                    }
                }
                catch (C.SqlException sqlExc)
                {
                    if (sqlExc.Number == -2)
                    {
                        Console.WriteLine("Query Error Exec:{0} Error Code:{1} Error Message:{2}", QueryText, sqlExc.Number, sqlExc.Message);
                        Console.WriteLine();
                        SqlConnection.ResetStatistics();
                        SqlConnection.Close();
                        stopWatchRealTime.Reset();
                        continue;
                    }
                    else
                    {
                        Console.WriteLine("---- Unknown Error: " + sqlExc.Number.ToString() + '-' + sqlExc.Message);
                        Console.WriteLine();
                        break;
                    }
                }
               }
            return returnBool;
        }

 

 

Output example: 

 

Jose_Manuel_Jurado_0-1640703375935.png

 

Enjoy!

1 Comment
%3CLINGO-SUB%20id%3D%22lingo-sub-3047076%22%20slang%3D%22en-US%22%3ELesson%20Learned%20%23180%3A%20Creating%20a%20retry-logic%20for%20TSQL%20command%20execution.%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-3047076%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%3EAs%20you%20know%2C%20one%20of%20the%20recommendations%20that%20we%20have%20in%20Azure%20SQL%20Database%20is%20to%20have%20a%20connection%20retry-logic%2C%20however%2C%20I%20would%20like%20to%20share%20with%20you%20other%20recommendation%20for%20command%20execution.%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSPAN%3EI%20developed%20the%20following%20piece%20of%20code%20that%20receives%2C%20four%20parameters.%26nbsp%3B%3C%2FSPAN%3E%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3E%3CSTRONG%3EConnectionString%3A%3C%2FSTRONG%3E%20Contains%20the%20connection%20string.%3C%2FLI%3E%0A%3CLI%3E%3CSTRONG%3EQueryText%3A%3C%2FSTRONG%3E%20Contains%20the%20query%20to%20execute.%3C%2FLI%3E%0A%3CLI%3E%3CSTRONG%3EretryIntervalSeconds%3A%3C%2FSTRONG%3E%20how%20much%20time%20the%20command%20timeout%20will%20be%20at%20the%20begining.%3C%2FLI%3E%0A%3CLI%3E%3CSTRONG%3EHowManyRetries%3A%3C%2FSTRONG%3E%20how%20many%20time%20the%20execution%20will%20be%20retried%20until%20fails.%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSPAN%3EBasically%2C%20as%20you%20could%20see%20in%20the%20example%20source%20code%20the%20operation%20will%20be%3A%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3E%3CSPAN%3E1)%20%3CSTRONG%3EConnect%20to%20the%20DB%3C%2FSTRONG%3E.%20This%20function%20has%20a%20connection%20retry-logic%20that%20we%20shared%20in%20previous%20article.%3C%2FSPAN%3E%3C%2FLI%3E%0A%3CLI%3E%3CSPAN%3E2)%20Try%20to%20execute%20the%20query%20(in%20this%20example%20will%20be%20NonQuery%20type)%20using%20the%20%3CSTRONG%3ECommandTimeout%20specified%3C%2FSTRONG%3E%20in%20the%20parameter%20value%20called%20retryIntervalSeconds.%26nbsp%3B%3C%2FSPAN%3E%3C%2FLI%3E%0A%3CLI%3E%3CSPAN%3E3)%20%3CSTRONG%3EIf%20the%20execution%20failed%2C%3C%2FSTRONG%3E%20the%20next%20command%20execution%20timeout%20will%20be%20multiple%20by%202.5.%20It%20and%20will%20be%20executed%20again%20until%20success%20or%20fails%20after%20retrying%20specified%20in%20the%20parameter%20value%20called%20HowManyRetries.%26nbsp%3B%3C%2FSPAN%3E%3C%2FLI%3E%0A%3CLI%3E%3CSPAN%3E4)%20Also%2C%20%3CSTRONG%3EI%20added%20an%20useful%20information%3C%2FSTRONG%3E%2C%20about%20how%20much%20the%20execution%20took%2C%20connection%20time%2C%20execution%20time%20and%20ConnectionID%2C%20etc..%3C%2FSPAN%3E%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3ESource%20code%20Example%3A%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%20%20%20%20%20%20%20%20public%20bool%20RunQueryWithRetriesNonQuery(string%20ConnectionString%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20string%20QueryText%2C%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20retryIntervalSeconds%20%3D%205%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20HowManyRetries%20%3D%205)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20bool%20returnBool%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20totalNrRows%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Stopwatch%20stopWatchWholeProcess%20%3D%20new%20Stopwatch()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Stopwatch%20stopWatchRealTime%20%3D%20new%20Stopwatch()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20ClsRetryLogic%20oClsRetry%20%3D%20new%20ClsRetryLogic()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20C.SqlConnection%20SqlConnection%20%3D%20new%20C.SqlConnection()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20C.SqlCommand%20SqlCommand%20%3D%20new%20C.SqlCommand(QueryText%2C%20SqlConnection)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20SqlConnection.StatisticsEnabled%20%3D%20true%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20stopWatchWholeProcess.Start()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20(int%20tries%20%3D%201%3B%20tries%20%26lt%3B%3D%20HowManyRetries%3B%20tries%2B%2B)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(oClsRetry.ConnectDBWithRetries(ConnectionString%2C%20SqlConnection%2C%20false))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(tries%20%26gt%3B%201)%20%7B%20retryIntervalSeconds%20%3D%20Convert.ToInt32(retryIntervalSeconds%20*%202.5)%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20SqlCommand.CommandTimeout%20%3D%20retryIntervalSeconds%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22Executing%20the%20query%20%7B0%7D%20-%20Attempt%20Nr.%3A%7B1%7D%20-%20CommandTimeout%3A%20%7B2%7D%20-%20ConnectionID%3A%7B3%7D%22%2C%20QueryText%2C%20tries%2C%20SqlCommand.CommandTimeout%2C%20SqlConnection.ClientConnectionId)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20stopWatchRealTime.Start()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20totalNrRows%20%3D%20(int)SqlCommand.ExecuteNonQuery()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20stopWatchRealTime.Stop()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20stopWatchWholeProcess.Stop()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeSpan%20ts%20%3D%20stopWatchWholeProcess.Elapsed%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20string%20elapsedTime%20%3D%20String.Format(%22%7B0%3A00%7D%3A%7B1%3A00%7D%3A%7B2%3A00%7D.%7B3%3A00%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ts.Hours%2C%20ts.Minutes%2C%20ts.Seconds%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ts.Milliseconds%20%2F%2010)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ts%20%3D%20stopWatchRealTime.Elapsed%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20string%20elapsedTimeRealTime%20%3D%20String.Format(%22%7B0%3A00%7D%3A%7B1%3A00%7D%3A%7B2%3A00%7D.%7B3%3A00%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ts.Hours%2C%20ts.Minutes%2C%20ts.Seconds%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ts.Milliseconds%20%2F%2010)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22Query%20Executed%20Text%3A%7B0%7D%20-%20Total%20ElapsedTime%3A%7B1%7D%20-%20Real%20Time%3A%7B5%7D%20-%20Rows%3A%7B2%7D%20-%20Tries%3A%7B3%7D%20-%20CommandTimeout%3A%7B4%7D%22%2CQueryText%2C%20elapsedTime%2C%20totalNrRows%2C%20tries%2C%20SqlCommand.CommandTimeout%2C%20elapsedTimeRealTime)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IDictionary%20currentStatistics%20%3D%20SqlConnection.RetrieveStatistics()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22----%20BytesReceived%3A%20%7B0%7D%22%2C(long)currentStatistics%5B%22BytesReceived%22%5D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22----%20BytesSent%3A%20%7B0%7D%22%2C%20(long)currentStatistics%5B%22BytesSent%22%5D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22----%20ExecutionTime%3A%20%7B0%7D%22%2C%20(long)currentStatistics%5B%22ExecutionTime%22%5D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22----%20ConnectionTime%3A%20%7B0%7D%22%2C%20(long)currentStatistics%5B%22ConnectionTime%22%5D%20)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20returnBool%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20SqlConnection.Close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22Connectivity%20Error..%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20catch%20(C.SqlException%20sqlExc)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine(%22Query%20Error%20Exec%3A%7B0%7D%20Error%20Code%3A%7B1%7D%20Error%20Message%3A%7B2%7D%22%2C%20QueryText%2C%20sqlExc.Number%2C%20sqlExc.Message%20)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20SqlConnection.ResetStatistics()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20SqlConnection.Close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20stopWatchRealTime.Reset()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20returnBool%3B%0A%20%20%20%20%20%20%20%20%7D%0A%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3EExample%20of%20output%3A%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22Jose_Manuel_Jurado_0-1640703375935.png%22%20style%3D%22width%3A%20840px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F336182iEC1704723FB8F45A%2Fimage-dimensions%2F840x219%3Fv%3Dv2%22%20width%3D%22840%22%20height%3D%22219%22%20role%3D%22button%22%20title%3D%22Jose_Manuel_Jurado_0-1640703375935.png%22%20alt%3D%22Jose_Manuel_Jurado_0-1640703375935.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EEnjoy!%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-3047076%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%3EAs%20you%20know%2C%20one%20of%20the%20recommendations%20that%20we%20have%20in%20Azure%20SQL%20Database%20is%20to%20have%20a%20connection%20retry-logic%2C%20however%2C%20I%20would%20like%20to%20share%20with%20you%20other%20recommendation%20for%20command%20execution.%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-TEASER%3E
Version history
Last update:
‎Dec 28 2021 07:35 AM
Updated by: