【发布时间】:2020-08-13 07:18:39
【问题描述】:
Cosmos DB 中的存储过程是事务性的,并且在具有乐观并发控制的隔离 snapshop 下运行。这意味着可能会发生写入冲突,但会检测到它们以便回滚事务。
如果发生这种冲突,Cosmos DB 是自动重试存储过程,还是客户端收到异常(可能是 HTTP 412 前置条件失败?)需要自己实现重试逻辑?
【问题讨论】:
标签: stored-procedures azure-cosmosdb
Cosmos DB 中的存储过程是事务性的,并且在具有乐观并发控制的隔离 snapshop 下运行。这意味着可能会发生写入冲突,但会检测到它们以便回滚事务。
如果发生这种冲突,Cosmos DB 是自动重试存储过程,还是客户端收到异常(可能是 HTTP 412 前置条件失败?)需要自己实现重试逻辑?
【问题讨论】:
标签: stored-procedures azure-cosmosdb
我尝试并行运行 100 个存储过程实例,通过读取文档(不设置 _etag)会产生写冲突,等待一段时间然后在该文档中递增一个整数属性(再次不设置_etag)。
到目前为止,在所有试验中,都没有发生错误,结果就像 100 次运行是按顺序运行的。所以初步的答案是:是的,Cosmos DB 会在写入冲突时自动重试运行 SP(或者可能通过锁定等其他方式强制执行事务隔离),因此客户端希望不必担心由于冲突而中止的 SP。
很高兴听取 Cosmos DB 工程师的意见,这是如何实现的:重试、锁定还是其他方式?
【讨论】:
您是正确的,因为这在任何地方都没有正确记录。以下是如何在存储过程中完成 OCC 检查:
function storedProcedureWithEtag(newItem)
{
var context = getContext();
var collection = context.getCollection();
var response = context.getResponse();
if (!newItem) {
throw 'Missing item';
}
// update the item to set changed time
newItem.ChangedTime = (new Date()).toISOString();
var etagForOcc = newItem._etag;
var upsertAccecpted = collection.upsertDocument(
collection.getSelfLink(),
newItem,
{ etag: etagForOcc }, // <-- Pass in the etag
function (err2, feed2, options2) {
if (err2) throw err2;
response.setBody(newItem);
}
);
if (!upsertAccecpted) {
throw "Unable to upsert item. Id: " + newItem.id;
}
}
信用:https://peter.intheazuresky.com/2016/12/22/documentdb-optimistic-concurrency-in-a-stored-procedure/
【讨论】:
SDK 不会重试 412,412 失败与 Optimistic Concurrency 相关,在这些情况下,您正在控制您正在传递的 ETag。预计用户通过读取最新版本的文档来处理412,获取更新的ETag,并使用更新后的值重试操作。
【讨论】: