Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tableclient.RetryPolicy Vs. TransientFaultHandling

Both myself and a colleague have been tasked with finding connection-retry logic for Azure Table Storage. After some searching, I found this really cool Enterprise Library suite, which contains the Microsoft.Practices.TransientFaultHandling namespace.

Following a few code examples, I ended up creating an Incremental retry strategy, and wrapping one of our storage calls with the retryPolicy's ExecuteAction callback handler :

/// <inheritdoc />
public void SaveSetting(int userId, string bookId, string settingId, string itemId, JObject value)
{
    // Define your retry strategy: retry 5 times, starting 1 second apart, adding 2 seconds to the interval each retry.
    var retryStrategy = new Incremental(5, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2));

    var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting(StorageConnectionStringName));            

    try
    {
        retryPolicy.ExecuteAction(() =>
        {
                var tableClient = storageAccount.CreateCloudTableClient();

                var table = tableClient.GetTableReference(SettingsTableName);

                table.CreateIfNotExists();

                var entity = new Models.Azure.Setting
                {
                    PartitionKey = GetPartitionKey(userId, bookId),
                    RowKey = GetRowKey(settingId, itemId),
                    UserId = userId,
                    BookId = bookId.ToLowerInvariant(),
                    SettingId = settingId.ToLowerInvariant(),
                    ItemId = itemId.ToLowerInvariant(),
                    Value = value.ToString(Formatting.None)
                };

                table.Execute(TableOperation.InsertOrReplace(entity));
            });
        }
        catch (StorageException exception)
        {
            ExceptionHelpers.CheckForPropertyValueTooLargeMessage(exception);

            throw;
        }
    }
}

Feeling awesome, I went to go show my colleague, and he smugly noted that we could do the same thing without having to include Enterprise Library, as the CloudTableClient object already has a setter for a retry policy. His code ended up looking like :

/// <inheritdoc />
public void SaveSetting(int userId, string bookId, string settingId, string itemId, JObject value)
{
        var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting(StorageConnectionStringName));
        var tableClient = storageAccount.CreateCloudTableClient();

        // set retry for the connection
        tableClient.RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(2), 3);

        var table = tableClient.GetTableReference(SettingsTableName);

        table.CreateIfNotExists();

        var entity = new Models.Azure.Setting
        {
            PartitionKey = GetPartitionKey(userId, bookId),
            RowKey = GetRowKey(settingId, itemId),
            UserId = userId,
            BookId = bookId.ToLowerInvariant(),
            SettingId = settingId.ToLowerInvariant(),
            ItemId = itemId.ToLowerInvariant(),
            Value = value.ToString(Formatting.None)
        };

        try
        {
            table.Execute(TableOperation.InsertOrReplace(entity));
        }
        catch (StorageException exception)
        {
            ExceptionHelpers.CheckForPropertyValueTooLargeMessage(exception);

            throw;
        }
}

My Question :

Is there any major difference between these two approaches, aside from their implementations? They both seem to accomplish the same goal, but are there cases where it's better to use one over the other?

like image 372
X3074861X Avatar asked Sep 23 '13 22:09

X3074861X


1 Answers

Functionally speaking both are the same - they both retries requests in case of transient errors. However there are few differences:

  • Retry policy handling in storage client library only handles retries for storage operations while transient fault handling retries not only handles storage operations but also retries SQL Azure, Service Bus and Cache operations in case of transient errors. So if you have a project where you're using more that storage but would like to have just one approach for handling transient errors, you may want to use transient fault handling application block.
  • One thing I liked about transient fault handling block is that you can intercept retry operations which you can't do with retry policy. For example, look at the code below:

        var retryManager = EnterpriseLibraryContainer.Current.GetInstance<RetryManager>();
        var retryPolicy = retryManager.GetRetryPolicy<StorageTransientErrorDetectionStrategy>(ConfigurationHelper.ReadFromServiceConfigFile(Constants.DefaultRetryStrategyForTableStorageOperationsKey));
        retryPolicy.Retrying += (sender, args) =>
        {
            // Log details of the retry.
            var message = string.Format(CultureInfo.InvariantCulture, TableOperationRetryTraceFormat, "TableStorageHelper::CreateTableIfNotExist", storageAccount.Credentials.AccountName,
                tableName, args.CurrentRetryCount, args.Delay);
            TraceHelper.TraceError(message, args.LastException);
        };
        try
        {
            var isTableCreated = retryPolicy.ExecuteAction(() =>
            {
                var table = storageAccount.CreateCloudTableClient().GetTableReference(tableName);
                return table.CreateIfNotExists(requestOptions, operationContext);
            });
            return isTableCreated;
        }
        catch (Exception)
        {
            throw;
        }
    

In the code example above, I could intercept retry operations and do something there if I want to. This is not possible with storage client library.

Having said all of this, it is generally recommended to go with storage client library retry policy for retrying storage operations as it is an integral part of the package and thus would be kept up to date with the latest changes to the library.

like image 191
Gaurav Mantri Avatar answered Oct 01 '22 07:10

Gaurav Mantri