I'm using version 4.3.0 of the Windows Azure Storage libraries for .NET. In my ATS repository class, I have a couple of batch delete methods that look like this:
public async Task DeleteAsync(IEnumerable<T> entities)
{
await ExecuteAsBatch(entities, (batch, entity) => batch.Delete(entity));
}
private async Task ExecuteAsBatch(IEnumerable<T> entities, Action<TableBatchOperation, T> batchAction)
{
var byPartition = entities.GroupBy(x => x.PartitionKey).ToList();
await byPartition.ForEachParallel(async group =>
{
// A maximum of 100 actions are allowed per batch job
var segments = group.ToList().ToSegmentedList(100);
await segments.ForEachParallel(async segment =>
{
var batch = new TableBatchOperation();
foreach (var entity in segment)
{
batchAction(batch, entity);
}
await Table.ExecuteBatchAsync(batch);
}, 10);
}, 10);
}
In other places in my code, that DeleteAsync()
method works correctly. However, in one particular place, I get this error message when executing the batch:
Unexpected Response Code for Operation: 0
Here's the call site:
private async Task MergeAtsOrganizationUserEvents(int organizationId, IEnumerable<CustomerUserEvent> fromEvents, CustomerUser to)
{
var toDelete = (await fromEvents.SelectParallel(async fromEvent =>
{
var pkey = AtsOrganizationUserEventByMinute.GetPartitionKey(organizationId, fromEvent.OccurredOn);
var rkey = AtsOrganizationUserEventByMinute.GetRowKey(fromEvent.OccurredOn, fromEvent.CustomerUserEventId);
return await Ats.OrganizationUserEventByMinute.FindByPartitionRowAsync(pkey, rkey);
})).Where(x => x != null).ToList();
var toInsert = toDelete
.Select(x => AtsOrganizationUserEventByMinute.FromBase(x.OrganizationId, x.OccurredOn, x.CookieId,
to.CustomerUserId, x))
.ToList();
try
{
await Ats.OrganizationUserEventByMinute.UpsertAsync(toInsert);
await Ats.OrganizationUserEventByMinute.DeleteAsync(toDelete);
}
catch (Exception ex)
{
_logger.Error("Unable to merge {0} AtsOrganizationEvents for org {1}, to customer user {2}: {3}",
toInsert.Count, organizationId, to.CustomerUserId, ex.CompleteMessage());
throw;
}
}
The UpsertAsync()
method above succeeds, but the DeleteAsync()
fails. Note that it fails to delete precisely the same entities that FindByPartitionRowAsync()
retrieved from the table, so I can't quite imagine how it could have anything to do with malformed entities or anything of that ilk.
Here's an example of one of the "toDelete" objects (in JSON format):
{
"CookieId":null,
"CustomerUserId":185766,
"CustomerUserEventId":3568687,
"OrganizationId":4190,
"EventName":"event1",
"SessionId":null,
"OccurredOn":"2014-10-20T18:17:09.9971379Z",
"UrlId":null,
"Url":null,
"ReferrerUrlId":null,
"ReferrerUrl":null,
"IsSynthetic":false,
"IpAddress":null,
"PartitionKey":"4190.2014.10.20",
"RowKey":"18.17.3568687",
"Timestamp":"2014-10-20T18:17:11.237+00:00",
"ETag":"W/\\" datetime'2014-10-20T18%3A17%3A11.237Z'\\""
}
Azure Storage error messages are notoriously and spectacularly unhelpful, and Googling has returned nothing about batch deletes failing with this particular error.
This fails both when using local development storage and in production.
Any thoughts?
'Unexpected Response Code for Operation: 0' basically means that the first operation in the batch failed. The index of the failed operation is returned in the error thrown so it makes it easier for users to go and change the specific operation in the batch that failed.
You can get more information about the request that failed and the error by catching the StorageException and checking:
exception.RequestInformation.HttpStatusCode
exception.RequestInformation.ExtendedErrorInformation.ErrorCode
exception.RequestInformation.ExtendedErrorInformation.ErrorMessage
The same information is also available in the OperationContext's last result if you use an OperationContext to track the request and use suitable method overloads that take in the OperationContext.
We will look at changing the error message in the future so it is less confusing. Thanks for the feedback!
Another cause of this is the use of invalid characters in the key fields. If you are googling this error message you might miss this answer:
Azure Table Storage RowKey restricted Character Patterns?
Characters Disallowed in Key Fields The following characters are not allowed in values for the PartitionKey and RowKey properties:
The forward slash (/) character
The backslash () character
The number sign (#) character
The question mark (?) character
Control characters from U+0000 to U+001F, including:
The horizontal tab (\t) character
The linefeed (\n) character
The carriage return (\r) character
Control characters from U+007F to U+009F
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With