-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Service Principal Retrieval Retry Logic Implementation
Overview
Implement exponential backoff retry logic when retrieving service principals after application creation, similar to the existing retry pattern used for retrieving newly created Private Access applications.
Issue Type
Enhancement
Priority
Medium
Background
Currently, the Set-ApplicationGroupAssignments function retrieves the service principal immediately after an application is created. Due to eventual consistency in Microsoft Entra ID, the service principal may not be immediately available, causing group assignment operations to fail.
This is similar to the issue already addressed for retrieving newly created applications in the New-PrivateAccessApplication function, which uses exponential backoff retry logic (lines 748-783).
Current Implementation
Location
- File:
Migrate2GSA/functions/GSA/Start-EntraPrivateAccessProvisioning.ps1 - Function:
Set-ApplicationGroupAssignments - Lines: ~979-1012
Current Code
if (-not $WhatIfPreference) {
try {
# Get the service principal for the application
$servicePrincipalParams = @{
Filter = "appId eq '$AppId'"
ErrorAction = 'Stop'
}
if ($DebugPreference -eq 'Continue') {
$servicePrincipalParams['Debug'] = $true
}
$servicePrincipal = Get-EntraBetaServicePrincipal @servicePrincipalParams
if (-not $servicePrincipal) {
Write-LogMessage "Service principal not found for application ID: $AppId" -Level ERROR -Component "GroupAssignment"
$result.Failed = $GroupNames.Count
$result.FailedGroups = $GroupNames
return $result
}
# ... rest of the code
}
catch {
Write-LogMessage "Failed to retrieve service principal: $_" -Level ERROR -Component "GroupAssignment"
$result.Failed = $GroupNames.Count
$result.FailedGroups = $GroupNames
return $result
}
}Proposed Solution
Implement exponential backoff retry logic similar to the pattern in New-PrivateAccessApplication:
# Retry logic to retrieve the service principal with exponential backoff
$maxRetries = 5
$baseDelay = 2 # seconds
$servicePrincipal = $null
for ($attempt = 1; $attempt -le $maxRetries; $attempt++) {
try {
Write-LogMessage "Attempting to retrieve service principal for AppId '$AppId' (attempt $attempt/$maxRetries)" -Level INFO -Component "GroupAssignment"
$servicePrincipalParams = @{
Filter = "appId eq '$AppId'"
ErrorAction = 'Stop'
}
if ($DebugPreference -eq 'Continue') {
$servicePrincipalParams['Debug'] = $true
}
$servicePrincipal = Get-EntraBetaServicePrincipal @servicePrincipalParams
if ($servicePrincipal) {
Write-LogMessage "Successfully retrieved service principal for AppId '$AppId' on attempt $attempt" -Level SUCCESS -Component "GroupAssignment"
break
}
# If no service principal found and not the last attempt, wait before retrying
if ($attempt -lt $maxRetries) {
$delay = $baseDelay * [math]::Pow(2, $attempt - 1) # Exponential backoff: 2, 4, 8, 16 seconds
Write-LogMessage "Service principal for AppId '$AppId' not found on attempt $attempt. Retrying in $delay seconds..." -Level WARN -Component "GroupAssignment"
Start-Sleep -Seconds $delay
}
}
catch {
$delay = $baseDelay * [math]::Pow(2, $attempt - 1)
if ($attempt -eq $maxRetries) {
Write-LogMessage "Failed to retrieve service principal for AppId '$AppId' after $maxRetries attempts. Final error: $_" -Level ERROR -Component "GroupAssignment"
$result.Failed = $GroupNames.Count
$result.FailedGroups = $GroupNames
return $result
}
Write-LogMessage "Failed to retrieve service principal for AppId '$AppId' on attempt $attempt. Retrying in $delay seconds... Error: $_" -Level WARN -Component "GroupAssignment"
Start-Sleep -Seconds $delay
}
}
if (-not $servicePrincipal) {
Write-LogMessage "Service principal not found for application ID: $AppId after $maxRetries retry attempts" -Level ERROR -Component "GroupAssignment"
$result.Failed = $GroupNames.Count
$result.FailedGroups = $GroupNames
return $result
}Benefits
- Increased Reliability: Handle eventual consistency delays in Microsoft Entra ID
- Better Error Messages: Clear logging of retry attempts and reasons for delays
- Consistent Pattern: Matches existing retry logic used elsewhere in the codebase
- Graceful Degradation: Multiple attempts before final failure
Retry Strategy Details
- Maximum Retries: 5 attempts (configurable)
- Base Delay: 2 seconds
- Backoff Schedule: 2s, 4s, 8s, 16s (exponential)
- Total Max Wait Time: ~30 seconds across all retries
- Retry Triggers:
- Service principal not found (null result)
- Exception during retrieval
Testing Considerations
- Test with newly created applications to ensure service principal is retrieved successfully
- Verify proper logging at each retry attempt
- Confirm graceful failure after max retries exceeded
- Test with existing applications (should succeed on first attempt)
Related Code
- Reference Implementation:
New-PrivateAccessApplicationfunction (lines 748-783) - Affected Function:
Set-ApplicationGroupAssignments - Dependencies:
Write-LogMessage,Get-EntraBetaServicePrincipal
Acceptance Criteria
- Implement retry logic with exponential backoff matching the pattern in
New-PrivateAccessApplication - Log retry attempts with clear messages (INFO level for attempts, WARN for retries, SUCCESS for completion)
- Handle both null results and exceptions during retrieval
- Maintain existing functionality for successful first-attempt retrievals
- Update function documentation if needed
- Test with newly created applications to verify retry logic works
Additional Notes
This enhancement improves the reliability of group assignment operations, especially in environments with high latency or eventual consistency delays. The retry pattern is already proven effective in the application creation flow.
Related Specification
See detailed specification document: Specs/20251012-ServicePrincipalRetryLogic.md