2015-09-11 5 views
6

La mia comprensione era che Azure CloudAppendBlob era al riparo da problemi di concorrenza in quanto è possibile solo aggiungere a questo storage BLOB e non è necessario confrontare E-tag. Come affermato da questo post:Errori Azure CloudAppendBlob con accesso simultaneo

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

specificamente:

Inoltre, aggiungere Blob supporta avere più clienti che scrivono allo stesso blob senza necessità di sincronizzazione (a differenza di blocco e pagina blob)

Tuttavia il seguente test dell'unità solleva:

412 la condizione di posizione aggiunta specificata non è stata soddisfatta.

dello stack 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 

Ecco il test di unità. Forse il servizio gestirà le richieste da diversi contesti ma non come questo come un parallelo?

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

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

forse mi manca qualcosa. Il motivo per cui sto cercando di farlo è che ho più lavori Web che possono tutti scrivere su questo blob di append e ho pensato che fosse per cosa fosse progettato?

+0

Ho anche appena provato questo da girare su più webjobs e scrivere del testo per lo stesso appendblob. Ho fatto lo stesso errore. – James

+0

Nota che sto usando la versione 5.0.2.0 di Microsoft.WindowsAzure.Storage (ho anche provato contro l'anteprima 5.0.3.0) – James

risposta

5

Dopo un po 'più di ricerca sembra che questo sia un problema reale.

Immagino che AppendBlobStorage sia abbastanza nuovo. (Ci sono anche altri problemi al momento con AppendBlobStorage vedere

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.)

Comunque ho risolto il problema utilizzando la variante AppendBlock piuttosto che AppendText come suggerito qui:

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

Il passare al metodo appendtext che supera il test unitario definito sopra

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

Perché stai chiamando cab.CreateOrReplace() anche in parallelo? Dovresti spostarlo su test_append_text_concurrency() prima di Parallel.Invoke()

+0

Con AzureBlobStorage devi creare prima di poter scrivere su di esso. Per esempio, poiché sto generando BLOB di file di registro in base al giorno, devo essere sicuro che il createorreplace sia fatto se il blob non esiste. Volevo anche testare questo per la concorrenza. – James

+0

Non sono sicuro che CreateOrReplace() sia simultaneo. Hai controllato? – Slava

+0

Neanche io! da qui il test. Il test unitario sopra riportato supera il punto ok dopo aver aggiunto la condizione di accesso e il blocco delle eccezioni. – James

0

Per le persone che hanno bisogno di una soluzione più generica a questo problema, ho creato un metodo di estensione:

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

Questa soluzione è più coerente con il modo di utilizzare altri metodi Append* su CloudAppendBlob.

-1

Si potrebbe provare AppendTextAsync. Sembrava funzionare per me in una situazione simile. Potrebbe anche funzionare la parola chiave lock.

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

L'uso di 'lock' serializzerà gli allegati piuttosto che lasciarli eseguire in parallelo come previsto dall'OP. Inoltre, ho riscontrato lo stesso problema dell'OP con 'AppendTextAsync'. –