简体   繁体   English

在Azure Functions中修改CosmosDb文档将触发无限循环

[英]Modifying CosmosDb document in Azure Functions triggers infinite loop

I try to update an document in Azure Functions when a CosmosDB document inserted/updated. 插入/更新CosmosDB文档时,我尝试更新Azure Functions中的文档。

However when I update the document inside the function, the function is triggered again and causes an infinite loop. 但是,当我在函数内部更新文档时,该函数再次被触发并导致无限循环。

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);
}

How can I prevent this? 我该如何预防? Can I use an CosmosDB out result with the modified document from the trigger? 我可以将CosmosDB输出结果与触发器中的已修改文档一起使用吗?

Update 1 更新1

I do not want to use another collection. 我不想使用其他集合。 This would double the pricing for CosmosDB. 这将使CosmosDB的价格翻倍。 I tried the following with an CosmosDB in- and output. 我使用CosmosDB输入和输出尝试了以下操作。 I get the same result however. 我得到相同的结果。 Infinite loop. 无限循环。

[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;
}

There is suggested way to do this mentioned in the following documentation https://docs.microsoft.com/en-us/azure/cosmos-db/serverless-computing-database 在以下文档中提到了建议的方法:https://docs.microsoft.com/zh-cn/azure/cosmos-db/serverless-computing-database

An Azure Cosmos DB trigger can be used with an output binding to a different Azure Cosmos DB container. Azure Cosmos DB触发器可以与绑定到其他Azure Cosmos DB容器的输出一起使用。 After a function performs an action on an item in the change feed you can write it to another container (writing it to the same container it came from would effectively create a recursive loop). 函数对变更供稿中的项目执行操作后,您可以将其写入另一个容器(将其写入来自其的相同容器将有效地创建递归循环)。 Or, you can use an Azure Cosmos DB trigger to effectively migrate all changed items from one container to a different container, with the use of an output binding. 或者,您可以使用Azure Cosmos DB触发器通过使用输出绑定有效地将所有更改的项目从一个容器迁移到另一个容器。

Input bindings and output bindings for Azure Cosmos DB can be used in the same Azure Function. Azure Cosmos DB的输入绑定和输出绑定可以在同一Azure函数中使用。 This works well in cases when you want to find certain data with the input binding, modify it in the Azure Function, and then save it to the same container or a different container, after the modification. 在您希望使用输入绑定查找某些数据,在Azure函数中对其进行修改,然后在修改之后将其保存到相同容器或不同容器的情况下,这种方法非常有用。

If you cannot use another collection then there is really no other option. 如果您不能使用其他集合,那么实际上没有其他选择。 The Trigger effectively triggers when a new document is inserted or updated. 当插入或更新新文档时,触发器将有效触发。 If your Trigger is updating / inserting documents in the same collection it is monitoring, it will effectively create a loop. 如果触发器在要监视的同一集合中更新/插入文档,它将有效地创建一个循环。

This is like using a QueueTrigger and inserting messages in the same Queue, the infinite loop applies to any Trigger mechanism. 这就像使用QueueTrigger并在同一Queue中插入消息一样,无限循环适用于任何Trigger机制。

One thing you could do though, is to filter those already updated: 但是,您可以做的一件事是过滤那些已经更新的内容:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM