在 Azure Functions 中修改 CosmosDb 文档会触发无限循环
Modifying CosmosDb document in Azure Functions triggers infinite loop
当 CosmosDB 文档 inserted/updated 时,我尝试更新 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;
}
以下文档中提到了执行此操作的建议方法
https://docs.microsoft.com/en-us/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. 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.
Input bindings and output bindings for Azure Cosmos DB can be used in
the same Azure Function. 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.
如果您不能使用另一个集合,那么就真的没有其他选择了。当插入或更新新文档时,触发器有效地触发。如果您的触发器正在更新/插入它正在监视的同一集合中的文档,它将有效地创建一个循环。
这就像使用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);
}
当 CosmosDB 文档 inserted/updated 时,我尝试更新 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;
}
以下文档中提到了执行此操作的建议方法 https://docs.microsoft.com/en-us/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. 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.
Input bindings and output bindings for Azure Cosmos DB can be used in the same Azure Function. 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.
如果您不能使用另一个集合,那么就真的没有其他选择了。当插入或更新新文档时,触发器有效地触发。如果您的触发器正在更新/插入它正在监视的同一集合中的文档,它将有效地创建一个循环。
这就像使用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);
}