2

So I have a function that simply downloads text from blob storage every 10 minutes and checks for a result. This function can run for days. But it often (roughly every day) fails before finishing with the following error.

Caused by: com.microsoft.azure.storage.StorageException: The condition specified using HTTP conditional header(s) is not met.

My code is pretty simple.

public String downloadTextBlob(CloudBlobDirectory dir, String filename) {
    try {
        return dir.getBlockBlobReference(filename).downloadText();
    } catch (StorageException | IOException | URISyntaxException e) {
        throw new WorkbenchRuntimeException(e.getMessage(), e);
    }
}

I the same issue posted here, and I was interested in the answer which talked about using an OperationContext to fix the issue. But the question wasn't on Java, and the answer didn't really explain what it was actually doing.

Here's the proposed solution (non java code)

 OperationContext context = new OperationContext();
 context.SendingRequest += (sender, e) => { 
     e.Request.Headers["if-match"] = "*";
 };

Can anyone explain what this is actually doing? And maybe how I can replicate this in Java, I notice there is an OperationContext in the Java azure storage sdk, and that I can call the .downloadText() with an operation context as a parameter. I'm just not sure what to do with OperationContext.

2
  • 1
    Is it possible that the blob’s content has changed while the download operation is running? Commented Jun 10, 2020 at 16:35
  • Yes, definitely. Commented Jun 10, 2020 at 16:39

1 Answer 1

3

First, I would encourage you to read about conditional headers in Azure Blob Storage here: https://learn.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations.

I haven't looked at the source code for the Java SDK but my guess is that downloadText() operation is performing multiple operations behind the scenes. In the first operation, it is getting the properties of the blob (like blob's length etc.) and in the next operation it is actually downloading the blob. As part of the first operation it also gets the blob's etag and it is passing the same etag to the 2nd operation in if-match header.

Now between the 1st and 2nd operation something changed with the blob that caused etag value to change. Since the 2nd request still used the old etag value and there's a mismatch between the etag, your request is failing with precondition failed. Presence of etag in if-match header instructs storage service to perform the operation only if the condition matches (i.e. etag matches). Since the etag doesn't match, you're getting this error.

To fix this, you need to use the following override of downloadText() method:

downloadText(final String charsetName, final AccessCondition accessCondition, BlobRequestOptions options, OperationContext opContext)

and specify an access condition with "*" value for if-match which essentially tells storage service to ignore the etag value. You can learn more about access condition here: https://learn.microsoft.com/en-us/java/api/com.microsoft.azure.storage.accesscondition?view=azure-java-legacy.

Your code would be something like (untested code):

AccessCondition accessCondition = AccessCondition.generateIfMatchCondition("*");

and use this access condition in your downloadText() method.

Sign up to request clarification or add additional context in comments.

1 Comment

i am having the same issue but problem is that i am using BlobTrigger. can we do this if-match in this case ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.