Skip to content

Commit 8a76581

Browse files
authored
Merge pull request #735 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 539c54a + f50cda4 commit 8a76581

File tree

2 files changed

+30
-76
lines changed

2 files changed

+30
-76
lines changed

Config/SchedulerRateLimits.json

Lines changed: 0 additions & 10 deletions
This file was deleted.

Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-UserTasksOrchestrator.ps1

Lines changed: 30 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,6 @@ function Start-UserTasksOrchestrator {
1717
$Filter = "PartitionKey eq 'ScheduledTask' and (TaskState eq 'Planned' or TaskState eq 'Failed - Planned' or (TaskState eq 'Pending' and Timestamp lt datetime'$30MinutesAgo') or (TaskState eq 'Running' and Timestamp lt datetime'$4HoursAgo'))"
1818
$tasks = Get-CIPPAzDataTableEntity @Table -Filter $Filter
1919

20-
$RateLimitTable = Get-CIPPTable -tablename 'SchedulerRateLimits'
21-
$RateLimits = Get-CIPPAzDataTableEntity @RateLimitTable -Filter "PartitionKey eq 'SchedulerRateLimits'"
22-
23-
$CIPPCoreModuleRoot = Get-Module -Name CIPPCore | Select-Object -ExpandProperty ModuleBase
24-
$CIPPRoot = (Get-Item $CIPPCoreModuleRoot).Parent.Parent
25-
$DefaultRateLimits = Get-Content -Path "$CIPPRoot/Config/SchedulerRateLimits.json" | ConvertFrom-Json
26-
$NewRateLimits = foreach ($Limit in $DefaultRateLimits) {
27-
if ($Limit.Command -notin $RateLimits.RowKey) {
28-
@{
29-
PartitionKey = 'SchedulerRateLimits'
30-
RowKey = $Limit.Command
31-
MaxRequests = $Limit.MaxRequests
32-
}
33-
}
34-
}
35-
36-
if ($NewRateLimits) {
37-
$null = Add-CIPPAzDataTableEntity @RateLimitTable -Entity $NewRateLimits -Force
38-
$RateLimits = Get-CIPPAzDataTableEntity @RateLimitTable -Filter "PartitionKey eq 'SchedulerRateLimits'"
39-
}
40-
41-
# Create a hashtable for quick rate limit lookups
42-
$RateLimitLookup = @{}
43-
foreach ($limit in $RateLimits) {
44-
$RateLimitLookup[$limit.RowKey] = $limit.MaxRequests
45-
}
46-
4720
$Batch = [System.Collections.Generic.List[object]]::new()
4821
$TenantList = Get-Tenants -IncludeErrors
4922
foreach ($task in $tasks) {
@@ -62,9 +35,12 @@ function Start-UserTasksOrchestrator {
6235
TaskState = 'Pending'
6336
}
6437
$task.Parameters = $task.Parameters | ConvertFrom-Json -AsHashtable
65-
$task.AdditionalProperties = $task.AdditionalProperties | ConvertFrom-Json
66-
6738
if (!$task.Parameters) { $task.Parameters = @{} }
39+
40+
# Cache Get-Command result to avoid repeated expensive reflection calls
41+
$CommandInfo = Get-Command $task.Command
42+
$HasTenantFilter = $CommandInfo.Parameters.ContainsKey('TenantFilter')
43+
6844
$ScheduledCommand = [pscustomobject]@{
6945
Command = $task.Command
7046
Parameters = $task.Parameters
@@ -77,13 +53,15 @@ function Start-UserTasksOrchestrator {
7753
Write-Host "Excluded Tenants from this task: $ExcludedTenants"
7854
$AllTenantCommands = foreach ($Tenant in $TenantList | Where-Object { $_.defaultDomainName -notin $ExcludedTenants }) {
7955
$NewParams = $task.Parameters.Clone()
80-
if ((Get-Command $task.Command).Parameters.TenantFilter) {
56+
if ($HasTenantFilter) {
8157
$NewParams.TenantFilter = $Tenant.defaultDomainName
8258
}
59+
# Clone TaskInfo to prevent shared object references
60+
$TaskInfoClone = $task.PSObject.Copy()
8361
[pscustomobject]@{
8462
Command = $task.Command
8563
Parameters = $NewParams
86-
TaskInfo = $task
64+
TaskInfo = $TaskInfoClone
8765
FunctionName = 'ExecScheduledCommand'
8866
}
8967
}
@@ -109,13 +87,15 @@ function Start-UserTasksOrchestrator {
10987

11088
$GroupTenantCommands = foreach ($ExpandedTenant in $ExpandedTenants | Where-Object { $_.value -notin $ExcludedTenants }) {
11189
$NewParams = $task.Parameters.Clone()
112-
if ((Get-Command $task.Command).Parameters.TenantFilter) {
90+
if ($HasTenantFilter) {
11391
$NewParams.TenantFilter = $ExpandedTenant.value
11492
}
93+
# Clone TaskInfo to prevent shared object references
94+
$TaskInfoClone = $task.PSObject.Copy()
11595
[pscustomobject]@{
11696
Command = $task.Command
11797
Parameters = $NewParams
118-
TaskInfo = $task
98+
TaskInfo = $TaskInfoClone
11999
FunctionName = 'ExecScheduledCommand'
120100
}
121101
}
@@ -125,14 +105,14 @@ function Start-UserTasksOrchestrator {
125105
Write-LogMessage -API 'Scheduler_UserTasks' -tenant $tenant -message "Failed to expand tenant group for task $($task.Name): $($_.Exception.Message)" -sev Error
126106

127107
# Fall back to treating as single tenant
128-
if ((Get-Command $task.Command).Parameters.TenantFilter) {
108+
if ($HasTenantFilter) {
129109
$ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant
130110
}
131111
$Batch.Add($ScheduledCommand)
132112
}
133113
} else {
134114
# Handle single tenant
135-
if ((Get-Command $task.Command).Parameters.TenantFilter) {
115+
if ($HasTenantFilter) {
136116
$ScheduledCommand.Parameters['TenantFilter'] = $task.Tenant
137117
}
138118
$Batch.Add($ScheduledCommand)
@@ -155,51 +135,35 @@ function Start-UserTasksOrchestrator {
155135
Write-Information 'Batching tasks for execution...'
156136
Write-Information "Total tasks to process: $($Batch.Count)"
157137

158-
if (($Batch | Measure-Object).Count -gt 0) {
159-
# Group commands by type and apply rate limits
160-
$CommandGroups = $Batch | Group-Object -Property Command
138+
if ($Batch.Count -gt 0) {
139+
# Group tasks by tenant instead of command type
140+
$TenantGroups = $Batch | Group-Object -Property { $_.Parameters.TenantFilter }
161141
$ProcessedBatches = [System.Collections.Generic.List[object]]::new()
162142

163-
foreach ($CommandGroup in $CommandGroups) {
164-
$CommandName = $CommandGroup.Name
165-
$Commands = [System.Collections.Generic.List[object]]::new($CommandGroup.Group)
166-
167-
# Get rate limit for this command (default to 100 if not found)
168-
$MaxItemsPerBatch = if ($RateLimitLookup.ContainsKey($CommandName)) {
169-
$RateLimitLookup[$CommandName]
170-
} else {
171-
100
172-
}
173-
174-
# Split into batches based on rate limit
175-
while ($Commands.Count -gt 0) {
176-
$BatchSize = [Math]::Min($Commands.Count, $MaxItemsPerBatch)
177-
$CommandBatch = [System.Collections.Generic.List[object]]::new()
178-
179-
for ($i = 0; $i -lt $BatchSize; $i++) {
180-
$CommandBatch.Add($Commands[0])
181-
$Commands.RemoveAt(0)
182-
}
143+
foreach ($TenantGroup in $TenantGroups) {
144+
$TenantName = $TenantGroup.Name
145+
$TenantCommands = [System.Collections.Generic.List[object]]::new($TenantGroup.Group)
183146

184-
$ProcessedBatches.Add($CommandBatch)
185-
}
147+
Write-Information "Creating batch for tenant: $TenantName with $($TenantCommands.Count) tasks"
148+
$ProcessedBatches.Add($TenantCommands)
186149
}
187150

188-
# Process each batch separately
151+
# Process each tenant batch separately
189152
foreach ($ProcessedBatch in $ProcessedBatches) {
190-
Write-Information "Processing batch with $($ProcessedBatch.Count) tasks..."
153+
$TenantName = $ProcessedBatch[0].Parameters.TenantFilter
154+
Write-Information "Processing batch for tenant: $TenantName with $($ProcessedBatch.Count) tasks..."
191155
Write-Information 'Tasks by command:'
192156
$ProcessedBatch | Group-Object -Property Command | ForEach-Object {
193157
Write-Information " - $($_.Name): $($_.Count)"
194158
}
195159

196-
# Create queue entry for each batch
197-
$Queue = New-CippQueueEntry -Name "Scheduled Tasks - Batch #$($ProcessedBatches.IndexOf($ProcessedBatch) + 1) of $($ProcessedBatches.Count)"
160+
# Create queue entry for each tenant batch
161+
$Queue = New-CippQueueEntry -Name "Scheduled Tasks - $TenantName"
198162
$QueueId = $Queue.RowKey
199-
$BatchWithQueue = $ProcessedBatch | Select-Object *, @{Name = 'QueueId'; Expression = { $QueueId } }, @{Name = 'QueueName'; Expression = { '{0} - {1}' -f $_.TaskInfo.Name, ($_.TaskInfo.Tenant -ne 'AllTenants' ? $_.TaskInfo.Tenant : $_.Parameters.TenantFilter) } }
163+
$BatchWithQueue = $ProcessedBatch | Select-Object *, @{Name = 'QueueId'; Expression = { $QueueId } }, @{Name = 'QueueName'; Expression = { '{0} - {1}' -f $_.TaskInfo.Name, $TenantName } }
200164

201165
$InputObject = [PSCustomObject]@{
202-
OrchestratorName = 'UserTaskOrchestrator'
166+
OrchestratorName = "UserTaskOrchestrator_$TenantName"
203167
Batch = @($BatchWithQueue)
204168
SkipLog = $true
205169
}

0 commit comments

Comments
 (0)