I try to update an document in Azure Functions when a CosmosDB document inserted/updated.
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?
I do not want to use another collection. This would double the pricing for CosmosDB. I tried the following with an CosmosDB in- and output. 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;
}
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.
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);
}