我发送一些服务的查询并获取结果。我想知道我是否已经得到同样的答案"回答"在过去。所以,我计划使用Azure Table作为缓存机制。
我做了这个小POC:
TableBatchOperation batchOperation = new TableBatchOperation();
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1");
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2");
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
table.ExecuteBatch(batchOperation);
当我第一次运行此代码时,它运行正常。在这结束时,我在表中有2行。
问题出在第二轮。当我执行此代码时:
TableBatchOperation batchOperation = new TableBatchOperation();
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1");
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2");
CachedUrl customer3 = new CachedUrl(Guid.Empty, "test3");
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
batchOperation.Insert(customer3);
table.ExecuteBatch(batchOperation);
(注意添加customer3
)
我期望获得的消息是:
我实际获得的是此异常(在ExecuteBatch()
方法上):
请求信息请求ID:5116ee8a-0002-0024-7ac1-415787000000 RequestDate:2016年11月18日星期五17:33:08 GMT StatusMessage:0:The 指定的实体已存在。错误码:EntityAlreadyExists
服务器发现#1实体存在,因此,跳过整个任务。
我如何得到预期的答案?
天真的解决方案是尝试逐个添加所有N个项目。但是这个解决方案是最慢的(N HTTP请求而不是1个请求)。
答案 0 :(得分:2)
Azure表存储批处理操作是原子操作,因此预计会在第一次失败的操作时返回。批处理操作可能包含1000个操作,表服务在检测到第一个故障后继续执行所有操作没有多大意义。
存储异常返回批处理中失败操作的实际索引以及与之相关的错误。
在下面的示例中,失败操作的索引为0,错误为EntityAlreadyExists:
0 :指定的实体已存在。 ErrorCode:EntityAlreadyExists
您可以编写捕获StorageException的重试逻辑,解析错误,如果错误是EntityAlreadyExists,则从批处理中删除该索引的操作,然后重新提交批处理操作。
请参阅我在Nuget中实现的azure Storage Exception解析器,它为您提取StorageException对象中的失败操作的索引和其他有用的信息,如HttpStatusCode:https://www.nuget.org/packages/AzureStorageExceptionParser/
为了避免在每次失败的操作中多次来回调用azure,以下是您可以探索的替代解决方案:
每次向表中插入实体时,也会插入第二个实体,该实体具有相同的分区键,该键只包含一个行键属性。让我们调用第二个实体RowKeyTracker实体。它将与原始实体具有相同的分区键,以便您可以执行批处理操作。它将具有一个唯一的行键,您可以知道它以查询它,它将具有一个属性,该属性是该分区的附加行键。如果RowKeyTracker实体已存在,则只需在每次插入新实体时将新行键附加到其分区键的行键属性,反之亦然,当您删除实体时,您也可以继续从RowKeyTracker中删除该行键实体。
因此,您可以使用此行键跟踪器实体来确定是否已插入该分区的行键,方法是先查询它。
您可以将此方法与第一种方法(重试)结合使用,以获得更强大的解决方案
答案 1 :(得分:0)
这是预期的行为。只要该批次中的任何实体发生故障,整个批次就会失败。
您可以做的一件事是使用InsertOrReplace
方法而不是Insert
。这将更新实体(如果存在),否则插入实体。
将TableOperation添加到插入的TableBatchOperation中 如果实体不存在,则将指定实体放入表中;如果 实体确实存在,然后用提供的内容替换它的内容 实体。