Cosmos DB 中的存储过程是否会在发生冲突时自动重试?

Are stored procedures in Cosmos DB automatically retried on conflict?

Cosmos DB 中的存储过程是事务性的,运行 在具有乐观并发控制的隔离 snapshop 下。这意味着可能会发生写入冲突,但会检测到它们,因此事务会回滚。

如果发生此类冲突,Cosmos DB 是自动重试存储过程,还是客户端收到异常(可能是 HTTP 412 前提条件失败?)并需要自己实现重试逻辑?

SDK 不会重试 412,412 失败与 Optimistic Concurrency 相关,在这些情况下,您控制着您传递的 ETag。期望用户通过阅读最新版本的文档来处理412,获取更新的ETag,并使用更新后的值重试操作。

我尝试了 运行并行存储过程的 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/