My understanding was that the Azure CloudAppendBlob was safe from concurrency issues as you can only append to this blob storage and it does not need to compare E-tags. As stated by this post:
specifically:
In addition, Append Blob supports having multiple clients writing to the same blob without any need for synchronization (unlike block and page blob)
However the following unit test raises:
412 the append position condition specified was not met.
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
Here is the unit test. Maybe the service will handle requests from different contexts but not like this as a parallel?
[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"));
}
Method in 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);
}
Maybe I'm missing something. The reason I'm trying to do this as I have multiple web jobs which can all write to this append blob and I figured this was what it was designed for?
After a bit more searching it looks like this is an actual problem.
I guess AppendBlobStorage is fairly new. (There are also other issues at the moment with AppendBlobStorage. see
Anyway I fixed the issue by using the AppendBlock varient rather than AppendText as suggested here:
https://azurekan.wordpress.com/2015/09/08/issues-with-adding-text-to-azure-storage-append-blob/
The change to the appendtext method which passes the unit test defined above
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);
}
}
}