RetryManager is schizophrenic

Ok, maybe I'm just not getting it but it seems like every line of code to access Sql Azure is a multi-day battle of asking for help on how to do something. Ok, so I try creating a connection using the following:

string connectionString = ConfigurationManager.ConnectionStrings["EnforcedVacation"].ConnectionString;
return new ReliableSqlConnection(connectionString);

And I get the error:

System.InvalidOperationException occurred
  HResult=-2146233079
  Message=The default RetryManager has not been set. Set it by invoking the RetryManager.SetDefault static method, or if you are using declarative configuration, you can invoke the RetryPolicyFactory.CreateDefault() method to automatically create the retry manager from the configuration file.
  Source=Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling
  StackTrace:
       at Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.RetryManager.get_Instance()
       at Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.ReliableSqlConnection..ctor(String connectionString)
       at UnitTestRepository.TestUtilities.GetConnection() in c:\src\EnforcedVacation\UnitTestRepository\TestUtilities.cs:line 44
  InnerException: 

So I then try (using random sample found on the web):

var retryInterval = TimeSpan.FromSeconds(3);
var strategy = new FixedInterval("fixed", 4, retryInterval);
var strategies = new List<RetryStrategy> { strategy };
var manager = new RetryManager(strategies, "fixed");
RetryManager.SetDefault(manager);

string connectionString = ConfigurationManager.ConnectionStrings["EnforcedVacation"].ConnectionString;
return new ReliableSqlConnection(connectionString);

and get:

System.InvalidOperationException occurred
  HResult=-2146233079
  Message=The RetryManager is already set.
  Source=Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling
  StackTrace:
       at Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.RetryManager.SetDefault(RetryManager retryManager, Boolean throwIfSet)
       at UnitTestRepository.TestUtilities.GetConnection() in c:\src\EnforcedVacation\UnitTestRepository\TestUtilities.cs:line 39
  InnerException: 

So apparently you must set the retry manager. But if you do, it's already set. What's the solution?

app.config is:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

	<configSections>
		<section name="RetryPolicyConfiguration" type="Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.Configuration.RetryPolicyConfigurationSettings, Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling, Version=5.0.1031.0, Culture=neutral, PublicKeyToken=null" requirePermission="true" />
		<section name="typeRegistrationProvidersConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.TypeRegistrationProvidersConfigurationSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
	</configSections>

	<typeRegistrationProvidersConfiguration>
		<clear />
		<add sectionName="RetryPolicyConfiguration" name="RetryPolicyConfiguration" />
	</typeRegistrationProvidersConfiguration>

	<RetryPolicyConfiguration defaultRetryStrategy="Fixed Interval Retry Strategy" defaultSqlConnectionRetryStrategy="Backoff Retry Strategy" defaultSqlCommandRetryStrategy="Incremental Retry Strategy" defaultAzureStorageRetryStrategy="Fixed Interval Retry Strategy" defaultAzureServiceBusRetryStrategy="Fixed Interval Retry Strategy">
		<incremental name="Incremental Retry Strategy" retryIncrement="00:00:01" retryInterval="00:00:01" maxRetryCount="10"/>
		<fixedInterval name="Fixed Interval Retry Strategy" retryInterval="00:00:01" maxRetryCount="10"/>
		<exponentialBackoff name="Backoff Retry Strategy" minBackoff="00:00:01" maxBackoff="00:00:30" deltaBackoff="00:00:10" maxRetryCount="10" fastFirstRetry="false"/>
	</RetryPolicyConfiguration>
	
	<appSettings>
		<add key="***" value="***"/>
	</appSettings>

	<connectionStrings>
		<add *** />
	</connectionStrings>
	<startup>
		
	<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup>

</configuration>
??? - thanks - dave

September 26th, 2014 5:31pm

Hi Dave,

Thank you for your question. 

I am trying to involve someone more familiar with this topic for a further look at this issue. Sometime delay might be expected from the job transferring. Your patience is greatly appreciated. 

Thank you for your understanding and support.

Regards,

Free Windows Admin Tool Kit Click here and download it now
September 30th, 2014 7:32am

It seems that this is not something that SQL Azure queue will be able to assist with. I suggest you to open a new technical case so an engineer with C# knowledge can work with them. So that you can get more help.
October 1st, 2014 1:38am

It seems that this is not something that SQL Azure queue will be able to assist with. I suggest you to open a new technical case so an engineer with C# knowledge can work with them. So that you can get more help.
Free Windows Admin Tool Kit Click here and download it now
October 1st, 2014 1:38am

Hi Dave, thanks for this post.  I've just started looking into this and I have to say the documentation is very poor / out of date.  Even following your example above the exception says you should call RetryPolicyFactory.CreateDefault() which I believe is a Lib version 5 call and is now deprecated (can anyone confirm?) since Lib version 6 (which still throws the same message).

Using your example I of course then ran into the same exception of 

The RetryManager is already set.

I then noticed there is a second param on RetryManager::SetDefault method which if set to false will stop an exception being thrown if the retry manager has already been set.   

 public static void SetDefault(RetryManager retryManager, bool throwIfSet = true);

So here I'm assuming that the config is being used and the second set of the RetryManager (in code) is then ignored!?  Have you found a cleaner (or even the correct) solution for this?

Thanks in advance for any help you can give!

Regards

Steve


  • Edited by APPERGY 17 hours 21 minutes ago
July 17th, 2015 9:56am

Hi Dave, thanks for this post.  I've just started looking into this and I have to say the documentation is very poor / out of date.  Even following your example above the exception says you should call RetryPolicyFactory.CreateDefault() which I believe is a Lib version 5 call and is now deprecated (can anyone confirm?) since Lib version 6 (which still throws the same message).

Using your example I of course then ran into the same exception of 

The RetryManager is already set.

I then noticed there is a second param on RetryManager::SetDefault method which if set to false will stop an exception being thrown if the retry manager has already been set.   

 public static void SetDefault(RetryManager retryManager, bool throwIfSet = true);

So here I'm assuming that the config is being used and the second set of the RetryManager (in code) is then ignored!?  Have you found a cleaner (or even the correct) solution for this?

Thanks in advance for any help you can give!

Regards

Steve


  • Edited by APPERGY 17 hours 10 minutes ago
Free Windows Admin Tool Kit Click here and download it now
July 17th, 2015 10:01am

I came up with something that works, but I have no idea if it's correct.

thanks - dave

July 17th, 2015 10:09am

Hi Dave, thanks for this post.  I've just started looking into this and I have to say the documentation is very poor / out of date.  Even following your example above the exception says you should call RetryPolicyFactory.CreateDefault() which I believe is a Lib version 5 call and is now deprecated (can anyone confirm?) since Lib version 6 (which still throws the same message).

Using your example I of course then ran into the same exception of 

The RetryManager is already set.

I then noticed there is a second param on RetryManager::SetDefault method which if set to false will stop an exception being thrown if the retry manager has already been set.   

 public static void SetDefault(RetryManager retryManager, bool throwIfSet = true);

So here I'm assuming that the config is being used and the second set of the RetryManager (in code) is then ignored!?  Have you found a cleaner (or even the correct) solution for this?

Thanks in advance for any help you can give!

Regards

Steve


  • Edited by APPERGY Friday, July 17, 2015 1:58 PM
Free Windows Admin Tool Kit Click here and download it now
July 17th, 2015 1:54pm

Hi Dave, thanks for this post.  I've just started looking into this and I have to say the documentation is very poor / out of date.  Even following your example above the exception says you should call RetryPolicyFactory.CreateDefault() which I believe is a Lib version 5 call and is now deprecated (can anyone confirm?) since Lib version 6 (which still throws the same message).

Using your example I of course then ran into the same exception of 

The RetryManager is already set.

I then noticed there is a second param on RetryManager::SetDefault method which if set to false will stop an exception being thrown if the retry manager has already been set.   

 public static void SetDefault(RetryManager retryManager, bool throwIfSet = true);

So here I'm assuming that the config is being used and the second set of the RetryManager (in code) is then ignored!?  Have you found a cleaner (or even the correct) solution for this?

Thanks in advance for any help you can give!

Regards

Steve


  • Edited by APPERGY Friday, July 17, 2015 1:58 PM
July 17th, 2015 1:54pm

Hi David,

I am assuming you are using version 6 of the Transient fault handling application block.  

With version 6 you have two ways to configure the transient fault handling block. They are programmatic configuration and declarative. In either case while performing different operations there is a setup step required to tell the block which retry strategy to use for performing retries. Also, if you do not tell the block which retry strategy to use you will get a "The default RetryManager has not been set error" . If you mix both approaches you will get  the error "The RetryManager is already set" the second time you try to initialize the block since you will typically initlialize the block only once during the start of the application.  The public static void SetDefault(RetryManager retryManager, bool throwIfSet = true) method provides an override switch which may be required in some edge cases. It is not advisable to mix both the approaches and programmatic approach is preferred. I have included some explanation at the end of this post on why programmatic is preferred, in case you are interested.

In order to use the ADO.net support in the transient fault handling block, the ReliableSqlConnection class needs to be configured to use a command retry and a connection retry policy. The connection retry will retry opening the connection when there are transient errors and the command retry with retry the command in cases where the execution of the command results in transient errors. Look at this post on some guidance on setting appropriate values for accessing SQL Database. The post also has some info on how to make your operations async and support retries which the transient fault handling block does not support out of the box.

Here are some code snippets on different ways to configure the block and use it.

1. Programmatic configuration:

a. Using the single arg constructor of ReliableSqlConnection class:

var foreGroundSqlStrategy = new ExponentialBackoff("default",3, TimeSpan.FromSeconds(0), TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(500));

            var backGroundJobSqlStrategy = new ExponentialBackoff("background",5, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(30), TimeSpan.FromMilliseconds(2));

            var retryStrategies = new[]

            {

                foreGroundSqlStrategy,

                backGroundJobSqlStrategy

            };

            RetryManager manager = new RetryManager(retryStrategies,"default");

// there has to be at  least 1 default which the block can use.

            RetryManager.SetDefault(manager);

            string connectionString = ConfigurationManager.ConnectionStrings["EnforcedVacation"].ConnectionString;

            using (var conn = new ReliableSqlConnection(connectionString))

            {

            }

b. private static void Using3ArgConstructor()

        {

            var retryStrategy = new ExponentialBackoff(3, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(2), TimeSpan.FromMilliseconds(750));

            var retryPolicy =

              new RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy>(retryStrategy);

            string connectionString = ConfigurationManager.ConnectionStrings["EnforcedVacation"].ConnectionString;

//Note if you use the 2 arg constructor you still have to follow approach 1.a. And set the default so that there is a default for the CommandRetry, We are explicity setting retry policies for command and connection here

        using (var conn = new ReliableSqlConnection(connectionString, retryPolicy, retryPolicy))

        {

        }

2. Configuration:

private static void UsingConfiguration()

        {

           var retryManager= RetryPolicyFactory.CreateDefault();

           string connectionString = ConfigurationManager.ConnectionStrings["EnforcedVacation"].ConnectionString;

            var conn = new ReliableSqlConnection(connectionString);

<o:p> </o:p>

 The declarative configuration support will pull all the transient fault handling block nugget packages (including the ones for caching, service bus etc. which you may not need) and make your application more bulky than needed. The declarative configuration is just present for (some) backward compatibility. We made this change after getting a lot of feedback from customers on the enterprise library blocks being too monolithic and having too many dependencies. Breaking changes are listed in the release notes.

Let me know if you have any questions.

Mani

MSFT

Free Windows Admin Tool Kit Click here and download it now
July 20th, 2015 8:42pm

Also note that programmatic support was available in earlier versions as well but harder to use.
July 20th, 2015 8:44pm

I went back and looked at our code (it's been awhile). I received guidance from a senior support person at Microsoft and he told me not to use the ReliableSqlConnection class and instead to use the TransientFaultHandling.RetryPolicy.ExecuteAction() method to handle retrying as needed.

And that the settings should all be defined in the .config file.

thanks - dave

Free Windows Admin Tool Kit Click here and download it now
July 21st, 2015 10:04am

Hi David, If you are using the Ado.net support available out of the box with the transient fault handling block you can create the Reliable connection instance or use extension methods (OpenWithRetry) to open the connection. I believe you are using a micro-ORM and in that case it makes sense to wrap the calls, as you mentioned. The only harm with using the configuration package is that you are pulling more dependencies than you need, as I mention earlier. Mani
July 21st, 2015 11:08am

Hi David, If you are using the Ado.net support available out of the box with the transient fault handling block you can create the Reliable connection instance or use extension methods (OpenWithRetry) to open the connection. I believe you are using a micro-ORM and in that case it makes sense to wrap the calls, as you mentioned. The only harm with using the configuration package is that you are pulling more dependencies than you need, as I mention earlier. Mani
Free Windows Admin Tool Kit Click here and download it now
July 21st, 2015 11:09am

Nope, not using an ORM - just plain old selects.

If you're with MSFT, please check with the senior DBAs on the Sql Database team for what is recommended. There are a million very different "correct" ways to do this out on the web, and most are sub-optimal.

July 21st, 2015 11:13am

Hi David, If you are using the Ado.net support available out of the box with the transient fault handling block you can create the Reliable connection instance or use extension methods (OpenWithRetry) to open the connection. I believe you are using a micro-ORM and in that case it makes sense to wrap the calls, as you mentioned. The only harm with using the configuration package is that you are pulling more dependencies than you need, as I mention earlier. Mani
Free Windows Admin Tool Kit Click here and download it now
July 21st, 2015 3:07pm

Hi David,

I am a part of the team which developed the transient fault handling library and working with the SQL team in case you are still facing issues. Wrapping calls is easier and it will work. Using the ReliableSQLConnection class or extension method is a more fine grained approach and ensures that only a subset of operations are retried and not the entire set of operations. Let me know if you still have any concerns about the issue you reported in this thread with the RetryManager. 

Mani Subramanian

MSFT

July 21st, 2015 5:35pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics