web-dev-qa-db-ja.com

挿入時に例外をスローするAzureテーブルストレージ:(409)競合

Azure Table Storageを使用してMVCアプリからの訪問者情報をログに記録していますが、次の例外がスローされることがあります。

[WebException: The remote server returned an error: (409) Conflict.]
   System.Net.HttpWebRequest.GetResponse() +1399
   Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync(RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Executor\Executor.cs:677

[StorageException: The remote server returned an error: (409) Conflict.]
   Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync(RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Core\Executor\Executor.cs:604
   Microsoft.WindowsAzure.Storage.Table.TableOperation.Execute(CloudTableClient client, CloudTable table, TableRequestOptions requestOptions, OperationContext operationContext) in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\ClassLibraryCommon\Table\TableOperation.cs:44

しばらく操作を行わなかった後、最初にWebサイトにアクセスしたときに発生するようです。その後、更新を押すと、ページが読み込まれ、それ以降はクリックするたびに問題が発生します。

例外の原因となっているコードの部分は次のとおりです。

  var visit = new TrackerVisitEntity(id, url, referer);
  var insertOperation = TableOperation.Insert(visit);
  _table.Execute(insertOperation);

更新

以下のコメントと両方の回答で特定されているように、問題は、ページが2回連続して読み込まれることがあり、パーティションキーとしてGUID(ユーザー固有)を使用していることです。 、および行キーとしての現在の日時。これにより、エンティティが重複し、例外が発生します。

アモールの答えはもっと詳細でしたが、土偶の簡単な解決策が私が使用したものだったので、私は彼の正解をマークしました。みんな、ありがとう。

5
littlecharva

409を回避するためにInsertOrReplaceの代わりにInsertを試すことができます。エンティティが存在しない場合は挿入し、存在する場合は既存のエンティティを置き換えます。それに関する警告は、eTagをチェックしないため、同じパーティションキーと行キーを持つ既存のエンティティがある場合、無条件に上書きします。

8
Dogu Arslan

Azure Table Storageでは、パーティションキーと行キーが一緒になってテーブルへのエントリの主キーとして機能します。この組み合わせは一意である必要があります。パーティションキーと行キーがすでにテーブルに存在する行を挿入する場合。 (409)競合例外をスローします。以下のコードで確認できます。

var visit = new TrackerVisitEntity(id, url, referer);

var insertOperation = TableOperation.Insert(visit);
try
{
    _table.Execute(insertOperation);
}
catch (StorageException ex)
{
    Trace.TraceInformation(string.Format("PartitionKey:{0},RowKey:{1}", visit.PartitionKey,visit.RowKey));
    TableOperation retrieveOperation = TableOperation.Retrieve<TrackerVisitEntity>(visit.PartitionKey, visit.RowKey);
    TableResult retrievedResult = _table.Execute(retrieveOperation);
    if (retrievedResult.Result != null)
    {
        Trace.TraceInformation("The entity is already exists in Table");
    }
}

例外が再度発生した場合、トレース情報は、パーティションキーと行キーがすでに存在するかどうかを示します。

RequestInformation.ExtendedErrorInformation.ErrorMessageから詳細な例外メッセージを取得することもできます。

catch (StorageException ex)
{
    Trace.TraceInformation(ex.RequestInformation.ExtendedErrorInformation.ErrorMessage); 
}
6
Amor

私が409のエラーを処理した方法は、次のように特定のcatchHttpStatusCodeすることです。

public TableResult AddAudioTest(AudioTestModel audioTestModel)
    {
        azureTableStorage = AzureTableStorage.TableConnection("AudioTests");
        TableOperation tableOperation = TableOperation.Insert(audioTestModel);
        try
        {
            TableResult tableInsertResult = azureTableStorage.Execute(tableOperation);
            return tableInsertResult;
        }
        catch (Microsoft.WindowsAzure.Storage.StorageException e) when (e.RequestInformation.HttpStatusCode == 409)
        {
            TableResult tableResult = new TableResult();
            tableResult.HttpStatusCode = e.RequestInformation.;
            tableResult.Result = e.Message;
            return tableResult;
        }
    }

お役に立てれば!

2
Jason Shave