@@ -17,5 +17,80 @@ function Start-DurableCleanup {
1717 param (
1818 [int ]$MaxDuration = 86400
1919 )
20- Write-Information " This cleanup is no longer required."
20+
21+ $WarningPreference = ' SilentlyContinue'
22+ $TargetTime = (Get-Date ).ToUniversalTime().AddSeconds(- $MaxDuration )
23+ $Context = New-AzDataTableContext - ConnectionString $env: AzureWebJobsStorage
24+ $InstancesTables = Get-AzDataTable - Context $Context | Where-Object { $_ -match ' Instances' }
25+
26+ $CleanupCount = 0
27+ $QueueCount = 0
28+
29+ $FunctionsWithLongRunningOrchestrators = [System.Collections.Generic.List [object ]]::new()
30+ $NonDeterministicOrchestrators = [System.Collections.Generic.List [object ]]::new()
31+
32+ foreach ($Table in $InstancesTables ) {
33+ $Table = Get-CippTable - TableName $Table
34+ $FunctionName = $Table.TableName -replace ' Instances' , ' '
35+ $Orchestrators = Get-CIPPAzDataTableEntity @Table - Filter " RuntimeStatus eq 'Running'" | Select-Object * - ExcludeProperty Input
36+ $Queues = Get-AzStorageQueue - Context $StorageContext - Name (' {0}*' -f $FunctionName ) | Select-Object - Property Name, ApproximateMessageCount, QueueClient
37+ $LongRunningOrchestrators = $Orchestrators | Where-Object { $_.CreatedTime.DateTime -lt $TargetTime }
38+
39+ if ($LongRunningOrchestrators.Count -gt 0 ) {
40+ $FunctionsWithLongRunningOrchestrators.Add (@ {' FunctionName' = $FunctionName })
41+ foreach ($Orchestrator in $LongRunningOrchestrators ) {
42+ $CreatedTime = [DateTime ]::SpecifyKind($Orchestrator.CreatedTime.DateTime , [DateTimeKind ]::Utc)
43+ $TimeSpan = New-TimeSpan - Start $CreatedTime - End (Get-Date ).ToUniversalTime()
44+ $RunningDuration = [math ]::Round($TimeSpan.TotalMinutes , 2 )
45+ Write-Information " Orchestrator: $ ( $Orchestrator.PartitionKey ) , created: $CreatedTime , running for: $RunningDuration minutes"
46+ if ($PSCmdlet.ShouldProcess ($_.PartitionKey , ' Terminate Orchestrator' )) {
47+ $Orchestrator = Get-CIPPAzDataTableEntity @Table - Filter " PartitionKey eq '$ ( $Orchestrator.PartitionKey ) '"
48+ $Orchestrator.RuntimeStatus = ' Failed'
49+ if ($Orchestrator.PSObject.Properties.Name -contains ' CustomStatus' ) {
50+ $Orchestrator.CustomStatus = " Terminated by Durable Cleanup - Exceeded max duration of $MaxDuration seconds"
51+ } else {
52+ $Orchestrator | Add-Member - MemberType NoteProperty - Name CustomStatus - Value " Terminated by Durable Cleanup - Exceeded max duration of $MaxDuration seconds"
53+ }
54+ Update-AzDataTableEntity @Table - Entity $Orchestrator
55+ $CleanupCount ++
56+ }
57+ }
58+ }
59+
60+ $NonDeterministicOrchestrators = $Orchestrators | Where-Object { $_.Output -match ' Non-Deterministic workflow detected' }
61+ if ($NonDeterministicOrchestrators.Count -gt 0 ) {
62+ $NonDeterministicOrchestrators.Add (@ {' FunctionName' = $FunctionName })
63+ foreach ($Orchestrator in $NonDeterministicOrchestrators ) {
64+ Write-Information " Orchestrator: $ ( $Orchestrator.PartitionKey ) is Non-Deterministic"
65+ if ($PSCmdlet.ShouldProcess ($_.PartitionKey , ' Terminate Orchestrator' )) {
66+ $Orchestrator = Get-CIPPAzDataTableEntity @Table - Filter " PartitionKey eq '$ ( $Orchestrator.PartitionKey ) '"
67+ $Orchestrator.RuntimeStatus = ' Failed'
68+ if ($Orchestrator.PSObject.Properties.Name -contains ' CustomStatus' ) {
69+ $Orchestrator.CustomStatus = ' Terminated by Durable Cleanup - Non-Deterministic workflow detected'
70+ } else {
71+ $Orchestrator | Add-Member - MemberType NoteProperty - Name CustomStatus - Value ' Terminated by Durable Cleanup - Non-Deterministic workflow detected'
72+ }
73+ Update-AzDataTableEntity @Table - Entity $Orchestrator
74+ $CleanupCount ++
75+ }
76+ }
77+ }
78+
79+ if (($LongRunningOrchestrators.Count -gt 0 -or $NonDeterministicOrchestrators.Count -gt 0 ) -and $Queues.ApproximateMessageCount -gt 0 ) {
80+ $RunningQueues = $Queues | Where-Object { $_.ApproximateMessageCount -gt 0 }
81+ foreach ($Queue in $RunningQueues ) {
82+ Write-Information " - Removing queue: $ ( $Queue.Name ) , message count: $ ( $Queue.ApproximateMessageCount ) "
83+ if ($PSCmdlet.ShouldProcess ($Queue.Name , ' Clear Queue' )) {
84+ $Queue.QueueClient.ClearMessagesAsync () | Out-Null
85+ }
86+ $QueueCount ++
87+ }
88+ }
89+ }
90+
91+ if ($CleanupCount -gt 0 -or $QueueCount -gt 0 ) {
92+ Write-LogMessage - api ' Durable Cleanup' - message " $CleanupCount orchestrators were terminated. $QueueCount queues were cleared." - sev ' Info' - LogData $FunctionsWithLongRunningOrchestrators
93+ }
94+
95+ Write-Information " Durable cleanup complete. $CleanupCount orchestrators were terminated. $QueueCount queues were cleared."
2196}
0 commit comments