[BUG] BlobClient.OpenWriteAsync does not fully honor overwrite: true
#47769
Labels
Client
This issue points to a problem in the data-plane of the library.
customer-reported
Issues that are reported by GitHub users external to the Azure organization.
needs-team-attention
Workflow: This issue needs attention from Azure service team or SDK team
question
The issue doesn't require a change to the product in order to be resolved. Most issues start as that
Service Attention
Workflow: This issue is responsible by Azure service team.
Storage
Storage Service (Queues, Blobs, Files)
Library name and version
Azure.Storage.Blobs 12.23.0
Describe the bug
When using
BlobClient.OpenWriteAsync
and writing to that withBlockBlobWriteStream.WriteAsync
, there is currently no way to makeoverwrite: true
always overwrite the blob.When setting
overwrite: true
in UploadAsync, that follows the pattern of Last Writer Wins by setting IfNoneMatch = "*"In the case of OpenWriteAsync with overwrite: true and WriteAsync + Dispose, OpenWriteAsync does not follow this pattern. It is always using Optimistic Concurrency. This is because OpenWriteAsync creates a 0 byte blob, gets the etag of that 0 byte blob, and then uses that in the match condition when committing the blocks uploaded during WriteAsync calls.
Therefore, in the case where a blob has been modified in between the OpenWriteAsync and the Dispose of the BlockBlobWriteStream, the blob is not overwritten, and a 412 is returned because the etag of the empty blob does not match the etag of the blob that was modified in between. I would expect the
Commit
within theDispose
of the BlockBlobWriteStream would use theIfNoneMatch = "*"
just like UploadAsync so the blob is written.We are also seeing this manifest in a different way which makes this scenario even more apparent. In our case, we are the only writer to the blob but we are still receiving this 412 because Storage is erroring out with a 500 on the Commit, but eventually writing the blobs we're committing, which changes the etag between built-in retries. The ordering is basically:
1234
2345
1234
1234 != 2345
This is frustrating in our code because while we're resilient to the 500s with retries, we are not resilient to the 412 as that's not a retriable error.
Expected behavior
OpenWriteAsync(overwrite: true)
WriteAsync()
-- Something modifies blob --
Dispose()
CommitInternal()
Should always write the blob being committed
Actual behavior
OpenWriteAsync(overwrite: true)
WriteAsync()
-- Something modifies blob --
Dispose()
CommitInternal()
Reproduction Steps
Environment
Example above uses LINQPad 8
The text was updated successfully, but these errors were encountered: