Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The correct way to delete and recreate a Windows Azure Storage Table = Error 409 Conflict - Code : TableBeingDeleted

Im really new to Windows Azure development and have a requirement to store some data in a windows azure storage table.

This table will really only exist to provide a quick lookup mechanism to some files which are located on azure storage drive.

Therefore I was planning on populating this table at application start up (ie in web application global application start up)

Rather than trying to maintain this table for changes the changes that could occur to the drive while the application is not running. Or as this drive is just a vhd of resources, we may well occasionally upload a new vhd.

So rather than the hassle of trying to maintain this. it is sufficient that this table be rebuild upon each application start.

I started to put together some code to check if the table already exists , and if it does delete it, and then recreate a new table.

var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorage"].ConnectionString);
var tableClient = storageAccount.CreateCloudTableClient();
var rmsTable = tableClient.GetTableReference("ResourceManagerStorage");
rmsTable.DeleteIfExists();
rmsTable.Create();

I had expected this would not work. And I get the following error:

The remote server returned an error: (409) Conflict. 

HTTP/1.1 409 Conflict
Cache-Control: no-cache
Transfer-Encoding: chunked
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: c6baf92e-de47-4a6d-82b3-4faec637a98c
x-ms-version: 2012-02-12
Date: Tue, 19 Mar 2013 17:26:25 GMT

166
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code>TableBeingDeleted</code>
  <message xml:lang="en-US">The specified table is being deleted. Try operation later.
RequestId:c6baf92e-de47-4a6d-82b3-4faec637a98c
Time:2013-03-19T17:26:26.2612698Z</message>
</error>
0

What is the correct way of doing this? Is there an event which can be subscribed to to let you know when the table as been deleted? ANy other suggestions on the best way to implement this?

like image 739
Kramer00 Avatar asked Mar 19 '13 19:03

Kramer00


2 Answers

From MSDN: "Note that deleting a table is likely to take at least 40 seconds to complete. If an operation is attempted against the table while it was being deleted, the service returns status code 409 (Conflict), with additional error information indicating that the table is being deleted."

The only way to deal with this is to create a table with a different name. This could be as simple as appending a timestamp or GUID to your name. Just be careful to clean up your garbage.

like image 161
IngisKahn Avatar answered Oct 08 '22 01:10

IngisKahn


If you need to use the same table name you can use an extension method:

public static class StorageExtensions
{
    #region Non-async

    public static bool SafeCreateIfNotExists(this CloudTable table, TimeSpan? timeout, TableRequestOptions requestOptions = null, OperationContext operationContext = null)
    {
        Stopwatch sw = Stopwatch.StartNew();
        if (timeout == null) timeout = TimeSpan.FromSeconds(41); // Assuming 40 seconds max time, and then some.
        do
        {
            if (sw.Elapsed > timeout.Value) throw new TimeoutException("Table was not deleted within the timeout.");

            try
            {
                return table.CreateIfNotExists(requestOptions, operationContext);
            }
            catch (StorageException e) when(IsTableBeingDeleted(e))
            {
                Thread.Sleep(1000);
            }
        } while (true);
    }

    #endregion

    #region Async

    public static async Task<bool> SafeCreateIfNotExistsAsync(this CloudTable table, TimeSpan? timeout, TableRequestOptions requestOptions = null, OperationContext operationContext = null, CancellationToken cancellationToken = default)
    {
        Stopwatch sw = Stopwatch.StartNew();
        if (timeout == null) timeout = TimeSpan.FromSeconds(41); // Assuming 40 seconds max time, and then some.
        do
        {
            if (sw.Elapsed > timeout.Value) throw new TimeoutException("Table was not deleted within the timeout.");

            try
            {
                return await table.CreateIfNotExistsAsync(requestOptions, operationContext, cancellationToken).ConfigureAwait(false);
            }
            catch (StorageException e) when(IsTableBeingDeleted(e))
            {
                // The table is currently being deleted. Try again until it works.
                await Task.Delay(1000);
            }
        } while (true);
    }

    #endregion

    private static bool IsTableBeingDeleted(StorageException e)
    {
        return
            e.RequestInformation.HttpStatusCode == 409
            &&
            e.RequestInformation.ExtendedErrorInformation.ErrorCode.Equals( TableErrorCodeStrings.TableBeingDeleted );
    }
}

WARNING! Be careful when you use this approach, because it blocks the thread. And it can go to the dead loop if third-party service (Azure) keeps generating these errors. The reason for this could be table locking, subscription expiration, service unavailability, etc.

like image 43
huha Avatar answered Oct 08 '22 02:10

huha