【问题标题】:The correct way to delete and recreate a Windows Azure Storage Table = Error 409 Conflict - Code : TableBeingDeleted删除和重新创建 Windows Azure 存储表的正确方法 = 错误 409 冲突 - 代码:TableBeingDeleted
【发布时间】:2013-03-08 15:50:45
【问题描述】:

我对 Windows Azure 开发非常陌生,并且需要将一些数据存储在 Windows azure 存储表中。

这个表实际上只是为了提供一种快速查找位于 Azure 存储驱动器上的文件的机制。

因此我计划在应用程序启动时填充此表(即在 Web 应用程序全局应用程序启动时)

与其尝试维护此表以更改应用程序未运行时驱动器可能发生的更改。或者由于这个驱动器只是一个资源的 vhd,我们可能偶尔会上传一个新的 vhd。

因此,而不是尝试维护这一点的麻烦。在每次应用程序启动时重建此表就足够了。

我开始整理一些代码来检查表是否已经存在,如果确实删除它,然后重新创建一个新表。

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

我原以为这行不通。我收到以下错误:

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

这样做的正确方法是什么?是否有可以订阅的事件让您知道表何时被删除?关于实现这一点的最佳方式的任何其他建议?

【问题讨论】:

    标签: c# azure azure-storage azure-table-storage azure-web-roles


    【解决方案1】:

    来自MSDN:“请注意,删除表可能需要至少 40 秒才能完成。如果在删除表时尝试对表执行操作,服务会返回状态代码 409(冲突),其中指示正在删除该表的附加错误信息。”

    解决此问题的唯一方法是创建一个具有不同名称的表。这可以像在您的姓名后附加时间戳或 GUID 一样简单。只是要小心清理你的垃圾。

    【讨论】:

    • 或者,您可以等待并重试,直到创建命令成功
    • 根据表的大小和许多其他因素,这可能是很长的时间。
    • 2015 年,同样的问题。我的解决方案:我保留一个元数据表来跟踪我的每个表的版本。所有查询首先访问元数据表以查看首先加载哪个表(X1,X2...Xn)。在删除/重新创建时,我加载到新的、更新元数据表,然后删除旧的。
    • 这对于拆除和重新创建数据库等的自动化环境脚本来说是一种痛苦。可能只需要继续尝试,等待直到它工作。
    • 值得注意的是,我在删除队列(而不是表)后遇到了这个问题
    【解决方案2】:

    如果需要使用相同的表名可以使用扩展方法:

    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 );
        }
    }
    

    警告!使用这种方法时要小心,因为它会阻塞线程。如果第三方服务 (Azure) 不断产生这些错误,它可能会进入死循环。造成这种情况的原因可能是表锁定、订阅过期、服务不可用等。

    【讨论】:

    • 哇,这不是一个好主意。通常,当逻辑依赖于第三方服务时,我会尽量避免使用 while(true)。 while(retryCnt > 0) 在这里会更好。
    • 当然你可以传递一些超时参数或者硬编码一些超时。但你会建议什么价值? 1分钟、2分钟、20分钟? IngisKahn 说“……可能需要至少 40 秒才能完成。”所以你需要一些高价值,如果你再等一秒钟,你永远不知道这个过程是否会完成。如果服务不可用或存在其他问题,我无法想象 MS 返回相同的错误 TableErrorCodeStrings.TableBeingDeleted。因此,如果有人添加超时,我会建议一个相当高的值。
    • 您可以使方法异步并将Thread.Sleep(2000) 替换为await Task.Delay(2000) - 这样线程不会被阻塞。
    猜你喜欢
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多