diff --git a/infra/app/db.bicep b/infra/app/db.bicep index b1cdab6..d2c5521 100644 --- a/infra/app/db.bicep +++ b/infra/app/db.bicep @@ -18,6 +18,11 @@ param containers array = [ id: 'VirusTotal' partitionKey: '/id' } + { + name: 'Leases' + id: 'Leases' + partitionKey: '/id' + } ] param databaseName string = '' diff --git a/src/backend/CosmosTodoItemTrigger.cs b/src/backend/CosmosTodoItemTrigger.cs new file mode 100644 index 0000000..805954d --- /dev/null +++ b/src/backend/CosmosTodoItemTrigger.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Logging; +using backend.Entities; +using backend.Models; +using System.Threading.Tasks; +using Microsoft.Azure.WebJobs.Extensions.DurableTask; +namespace backend +{ + public class CosmosTodoItemTrigger + { + [FunctionName("CosmosTodoItemTrigger")] + public async Task Run( + [CosmosDBTrigger( + databaseName: "%CosmosDatabaseName%", + containerName: "TodoItem", + Connection = "CosmosConnectionOptions", + LeaseContainerName = "Leases", + StartFromBeginning = true, + CreateLeaseContainerIfNotExists = false)] IReadOnlyList input, + [CosmosDB( + databaseName: "%CosmosDatabaseName%", + containerName: "TodoItem", + Connection = "CosmosConnectionOptions")] + IAsyncCollector output, + [DurableClient] IDurableEntityClient durableEntityClient) + { + if (input != null && input.Count > 0) + { + foreach (var item in input) + { + bool updated = await UpdateDbState(output, item); + + if (!updated) + { + await UpdateEntityState(durableEntityClient, item); + } + } + } + } + + private async Task UpdateDbState(IAsyncCollector output, TodoItem item) + { + if (item.State != TodoItemState.Overdue && item.IsOverdue()) + { + item.State = TodoItemState.Overdue; + item.UpdatedDate = DateTimeOffset.UtcNow.DateTime; + await output.AddAsync(item); + + return true; + } + + return false; + } + + private async Task UpdateEntityState(IDurableEntityClient durableEntityClient, TodoItem item) + { + if (item.DueDate is null || item.IsOverdue()) + { + await durableEntityClient.SignalEntityAsync(item.Id, proxy => proxy.Delete()); + return; + } + + await durableEntityClient.SignalEntityAsync(item.Id, proxy => proxy.Create(item)); + } + } +}