Workoho.Automation.Azure/Public/Wait-Auto_AzAutomationConcurrentJob.ps1
<# .SYNOPSIS This script is used to wait for concurrent jobs in Azure Automation. .DESCRIPTION This script checks for the presence of concurrent jobs in Azure Automation and waits until the current job is at the top of the queue. .EXAMPLE PS> Wait-Auto_AzAutomationConcurrentJob Waits for concurrent jobs in Azure Automation. #> function Wait-Auto_AzAutomationConcurrentJob { [CmdletBinding()] Param() Write-Auto_FunctionBegin $MyInvocation if ($IsAzureAutomationJob) { #region [COMMON] CONNECTIONS --------------------------------------------------- # Implicitly connect to Azure Graph API using the Connect-Auto_MgGraph command. # This will ensure the connections are established in the correct order, while still retrieving the necessary environment variables. Connect-Auto_MgGraph #endregion --------------------------------------------------------------------- if ([string]::IsNullOrEmpty($env:AZURE_AUTOMATION_ResourceGroupName)) { Throw 'Missing environment variable $env:AZURE_AUTOMATION_ResourceGroupName.' } if ([string]::IsNullOrEmpty($env:AZURE_AUTOMATION_AccountName)) { Throw 'Missing environment variable $env:AZURE_AUTOMATION_AccountName.' } if ([string]::IsNullOrEmpty($env:AZURE_AUTOMATION_RUNBOOK_Name)) { Throw 'Missing environment variable $env:AZURE_AUTOMATION_RUNBOOK_Name.' } if ($env:AZURE_AUTOMATION_ResourceGroupName -and $env:AZURE_AUTOMATION_AccountName -and $env:AZURE_AUTOMATION_RUNBOOK_Name) { $DoLoop = $true $RetryCount = 1 $MaxRetry = 300 $WaitMin = 25000 $WaitMax = 30000 $WaitStep = 100 $warningInterval = 180 # 3 minutes / 1 second sleep $warningCounter = $warningInterval # Start with a warning after the first sleep do { $activeJobs = New-Object System.Collections.ArrayList try { # Get all jobs for the runbook and process using pipeline to avoid memory issues $params = @{ Path = "$($env:AZURE_AUTOMATION_AccountId)/jobs?api-version=2023-11-01" ErrorAction = 'Stop' Verbose = $false Debug = $false } (Invoke-Auto_AzRestMethod $params).Content.value.properties | & { process { if ( $_.status -eq 'Running' -or $_.status -eq 'Queued' -or $_.status -eq 'New' -or $_.status -eq 'Activating' -or $_.status -eq 'Resuming' ) { [void] $activeJobs.Add( @{ jobId = $_.jobId creationTime = [DateTime]::Parse($_.creationTime).ToUniversalTime() } ) } } } } catch { Throw $_ } $activeJobs = @($activeJobs | Sort-Object -Property creationTime) $currentJob = $activeJobs | Where-Object { $_.jobId -eq $PSPrivateMetadata.JobId } if ($null -eq $currentJob) { $waitTime = $((Get-Random -Minimum (3000 / $WaitStep) -Maximum (8000 / $WaitStep)) * $WaitStep) $waitTimeInSeconds = [Math]::Round($waitTime / 1000, 2) Write-Warning "[INFO]: - Current job not found (yet) in the list of active jobs. Waiting for $waitTimeInSeconds seconds to appear." Start-Sleep -Milliseconds $waitTime } elseif ($currentJob.jobId -eq $activeJobs[0].jobId) { Write-Verbose "[INFO]: - Current job is at the top of the queue." $DoLoop = $false $return = $true } elseif ($RetryCount -ge $MaxRetry) { Write-Warning "[INFO]: - Maximum retry count reached. Exiting loop." $DoLoop = $false $return = $false } else { $RetryCount++ $waitTime = $((Get-Random -Minimum ($WaitMin / $WaitStep) -Maximum ($WaitMax / $WaitStep)) * $WaitStep) $waitTimeInSeconds = [Math]::Round($waitTime / 1000, 2) $warningCounter += $waitTimeInSeconds $rank = 1 for ($i = 0; $i -lt $activeJobs.Length; $i++) { if ($activeJobs[$i].jobId -eq $currentJob.jobId) { $rank = $i + 1 break } } if ($warningCounter -ge $warningInterval) { Write-Warning "[INFO]: - Waiting for concurrent jobs: I am at rank $($rank) out of $($activeJobs.Count) active jobs. Waiting for $waitTimeInSeconds seconds. Next status update will be in $warningInterval seconds." $warningCounter = 0 } else { Write-Verbose "[INFO]: - Waiting for concurrent jobs: I am at rank $($rank) out of $($activeJobs.Count) active jobs. Waiting for $waitTimeInSeconds seconds." } Start-Sleep -Milliseconds $waitTime } Clear-Variable -Name activeJobs Clear-Variable -Name currentJob [System.GC]::Collect() [System.GC]::WaitForPendingFinalizers() } while ($DoLoop) } } else { Write-Verbose '[COMMON]: - Not running in Azure Automation: Concurrency check NOT ACTIVE.' $return = $true } Write-Auto_FunctionEnd $MyInvocation return $return } |