【问题标题】:Modifying CosmosDb document in Azure Functions triggers infinite loop在 Azure Functions 中修改 CosmosDb 文档会触发无限循环
【发布时间】:2019-03-04 09:40:34
【问题描述】:

我尝试在插入/更新 CosmosDB 文档时更新 Azure Functions 中的文档。

但是,当我在函数内更新文档时,该函数再次被触发并导致无限循环。

private static DocumentClient _documentClient = new DocumentClient(new Uri(serviceEndpoint), key);

[FunctionName(nameof(MyFunction))]
public static async Task RunAsync([CosmosDBTrigger(
    databaseName: "MyDatabase",
    collectionName: "MyCollection",
    ConnectionStringSetting = "MyDbConnectionString",
    LeaseCollectionName = "leases",
    CreateLeaseCollectionIfNotExists = true,
    LeaseCollectionPrefix = nameof(MyFunction))]IReadOnlyList<Document> input,
    ILogger log)
{
    var replacementsTasks = new List<Task>();

    foreach (var item in input)
    {
        item.SetPropertyValue("Updated", true);
        replacementsTasks.Add(_documentClient.ReplaceDocumentAsync(item));
    }

    await Task.WhenAll(replacementsTasks);
}

如何防止这种情况发生?我可以将 CosmosDB 输出结果与触发器中的已修改文档一起使用吗?

更新 1

我不想使用其他集合。这将使 CosmosDB 的价格翻倍。我使用 CosmosDB 输入和输出尝试了以下操作。但是,我得到了相同的结果。无限循环。

[FunctionName(nameof(DownloadImages))]
public static void Run(
    [CosmosDBTrigger(
    databaseName: database,
    collectionName: collection,
    ConnectionStringSetting = connectionStringName,
    LeaseCollectionName = "leases",
    CreateLeaseCollectionIfNotExists = true,
    LeaseCollectionPrefix = nameof(MyFunction))]IReadOnlyList<Document> input,
    [CosmosDB(database, collection, Id = "id", ConnectionStringSetting = connectionStringName)] out dynamic document,
    ILogger log)
{

    if(input.Count != 1) throw new ArgumentException();

    document = input.Single();
    document.myValue = true;
}

【问题讨论】:

  • 您可以创建一个跨容器共享 RU 的数据库。

标签: c# azure azure-functions azure-cosmosdb infinite-loop


【解决方案1】:

如果您不能使用其他集合,那么确实没有其他选择。当插入或更新新文档时,触发器有效地触发。如果您的触发器在它正在监视的同一集合中更新/插入文档,它将有效地创建一个循环。

这就像使用 QueueTrigger 并在同一个 Queue 中插入消息,无限循环适用于任何 Trigger 机制。

你可以做的一件事是过滤那些已经更新的:

private static DocumentClient _documentClient = new DocumentClient(new Uri(serviceEndpoint), key);

[FunctionName(nameof(MyFunction))]
public static async Task RunAsync([CosmosDBTrigger(
    databaseName: "MyDatabase",
    collectionName: "MyCollection",
    ConnectionStringSetting = "MyDbConnectionString",
    LeaseCollectionName = "leases",
    CreateLeaseCollectionIfNotExists = true,
    LeaseCollectionPrefix = nameof(MyFunction))]IReadOnlyList<Document> input,
    ILogger log)
{
    var replacementsTasks = new List<Task>();

    foreach (var item in input)
    {
        if (!item.GetPropertyValue<bool>("Updated")) {
            item.SetPropertyValue("Updated", true);
            replacementsTasks.Add(_documentClient.ReplaceDocumentAsync(item));
        }
    }

    await Task.WhenAll(replacementsTasks);
}

【讨论】:

    【解决方案2】:

    以下文档中提到了执行此操作的建议方法 https://docs.microsoft.com/en-us/azure/cosmos-db/serverless-computing-database

    Azure Cosmos DB 触发器可以与输出绑定一起使用到 不同的 Azure Cosmos DB 容器。在一个函数执行一个 对更改提要中的项目执行的操作,您可以将其写入另一个 容器(将它写到它来自的同一个容器中 有效地创建递归循环)。或者,您可以使用 Azure Cosmos 数据库触发器有效地从一个容器迁移所有更改的项目 使用输出绑定到不同的容器。

    Azure Cosmos DB 的输入绑定和输出绑定可用于 相同的 Azure 函数。这在您想要的情况下效果很好 使用输入绑定查找某些数据,在 Azure 中对其进行修改 函数,然后将其保存到同一个容器或不同的容器中 容器,修改后。

    【讨论】:

    • 我更新了我的问题。另一个集合不是一个选项。输入和输出绑定将是完美的,但不起作用。
    猜你喜欢
    • 2020-05-23
    • 1970-01-01
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 2019-11-20
    • 2012-04-28
    相关资源
    最近更新 更多