2015-09-11 3 views
6

Ma compréhension était que le CloudAppendBlob Azure était à l'abri des problèmes de simultanéité, car vous ne pouvez que l'ajouter à ce stockage BLOB et il n'a pas besoin de comparer les E-tags. Comme indiqué par ce poste:Azure Erreurs CloudAppendBlob avec accès simultané

http://blogs.msdn.com/b/windowsazurestorage/archive/2015/04/13/introducing-azure-storage-append-blob.aspx

spécifiquement:

En outre, Append Blob soutient avoir plusieurs clients d'écriture à la même blob sans besoin de synchronisation (contrairement à bloc et blob page)

Cependant, le test unitaire suivant pose:

412 la condition de position d'ajout spécifiée n'a pas été remplie.

pile trace

Microsoft.WindowsAzure.Storage.Blob.BlobWriteStream.Flush() 
Microsoft.WindowsAzure.Storage.Blob.BlobWriteStream.Commit() 
Microsoft.WindowsAzure.Storage.Blob.CloudAppendBlob.UploadFromStreamHelper 
Microsoft.WindowsAzure.Storage.Blob.CloudAppendBlob.AppendFromStream 
Microsoft.WindowsAzure.Storage.Blob.CloudAppendBlob.AppendFromByteArray 
Microsoft.WindowsAzure.Storage.Blob.CloudAppendBlob.AppendText 

Voici le test unitaire. Peut-être que le service va gérer les demandes de différents contextes mais pas comme ça en parallèle?

[TestMethod] 
    public void test_append_text_concurrency() 
    { 
     AppendBlobStorage abs = new AppendBlobStorage(new TestConnectConfig(), "testappendblob"); 

     string filename = "test-concurrent-blob"; 

     abs.Delete(filename);      

     Parallel.Invoke(
      () => { abs.AppendText(filename, "message1\r\n"); }, 
      () => { abs.AppendText(filename, "message2\r\n"); } 
     ); 

     string text = abs.ReadText(filename); 

     Assert.IsTrue(text.Contains("message1")); 
     Assert.IsTrue(text.Contains("message2")); 
    } 

Méthode AppendBlobStorage

public void AppendText(string filename, string text) 
    { 
     CloudAppendBlob cab = m_BlobStorage.BlobContainer.GetAppendBlobReference(filename); 

     // Create if it doesn't exist 
     if (!cab.Exists()) 
     { 
      try 
      { 
       cab.CreateOrReplace(AccessCondition.GenerateIfNotExistsCondition(), null, null); 
      } 
      catch { } 
     } 

     // Append the text 
     cab.AppendText(text);  
    } 

Peut-être que je manque quelque chose. La raison pour laquelle j'essaye de faire ceci comme j'ai plusieurs travaux de Web qui peuvent tous écrire à cet append blob et j'ai pensé que c'était pour cela que c'était conçu?

+0

Je viens aussi de tester cela en tournant plusieurs webjobs et en écrivant du texte sur le même appendix. J'ai la même erreur. – James

+0

Notez que j'utilise la version 5.0.2.0 de Microsoft.WindowsAzure.Storage (j'ai également essayé contre l'aperçu de 5.0.3.0) – James

Répondre

5

Après un peu plus de recherche, il semble que ce soit un problème réel.

Je suppose que AppendBlobStorage est relativement nouveau. (Il y a aussi d'autres problèmes au moment de AppendBlobStorage voir

http://blogs.msdn.com/b/windowsazurestorage/archive/2015/09/02/issue-in-azure-storage-client-library-5-0-0-and-5-0-1-preview-in-appendblob-functionality.aspx.)

Quoi qu'il en soit je résolu le problème en utilisant le Varient de AppendBlock plutôt que AppendText comme suggéré ici:

https://azurekan.wordpress.com/2015/09/08/issues-with-adding-text-to-azure-storage-append-blob/

Le passer à la méthode appendicite qui réussit le test unitaire défini ci-dessus

public void AppendText(string filename, string text) 
    { 
     if (string.IsNullOrWhiteSpace(filename)) 
      throw new ArgumentException("filename cannot be null or empty"); 

     if (!string.IsNullOrEmpty(text)) 
     { 
      CloudAppendBlob cab = m_BlobStorage.BlobContainer.GetAppendBlobReference(filename); 

      // Create if it doesn't exist 
      if (!cab.Exists()) 
      { 
       try 
       { 
        cab.CreateOrReplace(AccessCondition.GenerateIfNotExistsCondition(), null, null); 
       } 
       catch (StorageException) { } 
      } 

      // use append block as append text seems to have an error at the moment. 
      using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text))) 
      { 
       cab.AppendBlock(ms); 
      } 
     } 

    } 
0

Pourquoi appelez-vous cab.CreateOrReplace() également en parallèle? Vous devez le déplacer vers test_append_text_concurrency() avant Parallel.Invoke()

+0

Avec le AzureBlobStorage vous devez créer avant que vous puissiez écrire dedans. Puisque je génère des blobs de fichier journal basés sur le jour par exemple, je dois être sûr que le createorreplace est fait si le blob n'existe pas. Je voulais également tester cela pour la concurrence. – James

+0

Je ne suis pas sûr que CreateOrReplace() est concurrent. Avez-vous vérifié? – Slava

+0

Moi non plus! d'où le test. Le test d'unité ci-dessus dépasse ce point après avoir ajouté la condition d'accès et la capture d'exception. – James

0

Pour les personnes qui ont besoin d'une solution plus générique à ce problème, je créé une méthode d'extension:

public static async Task AppendTextConcurrentAsync(this CloudAppendBlob appendBlob, string content) 
{ 
    using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content))) 
    { 
     await appendBlob.AppendBlockAsync(stream); 
    } 
} 

Cette solution est plus cohérente avec la façon dont vous utilisez d'autres méthodes Append* sur CloudAppendBlob.

-1

Vous pourriez essayer AppendTextAsync. Cela a semblé fonctionner pour moi dans une situation similaire. L'utilisation du mot clé lock peut également fonctionner.

public void Log(string message) 
{ 
    lock (this.appendBlob) 
    { 
     appendBlob.AppendText(string.Format("[{0:s}] {1}{2}", DateTime.Now, message, Environment.NewLine)); 
    } 
} 
+0

L'utilisation de 'lock' sérialisera les ajouts plutôt que de les laisser fonctionner en parallèle comme prévu par l'OP. En outre, j'ai rencontré le même problème que l'OP avec 'AppendTextAsync'. –