-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
invoke-expressionwithretry.yml
100 lines (88 loc) · 3.58 KB
/
invoke-expressionwithretry.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
########################################################################
# Template: invoke-expressionwithretry.yml
# Description: Invoke a PowerShell expression, retrying the specified
# number of time on failure.
########################################################################
parameters:
# Number of time to retry calling the provided PowerShell expression.
# Set to -1 to retry indefinately.
- name: numberOfRetries
type: number
default: 10
# The PowerShell expression to execute. Expression is executed using
# 'Invoke-Expression -Command "& <expression>"'.
- name: expression
type: string
# Failures outside this time frame will restart the retry process.
- name: recentFailureThresholdInMinutes
type: number
default: 3
# Maximum time to wait between attempts. The retry wait time will be
# increased incrementally up until this number.
- name: maxRetryWaitTimeInMinutes
type: number
default: 6
# The task display name.
- name: displayName
type: string
# Number of times to retry task on failure.
- name: retryCountOnTaskFailure
type: number
default: 10
# Environment variables passed to the task.
- name: env
type: object
default: []
steps:
- pwsh: |
# Setup parameters
$succeedWithIssues = $false
$failureCount = 0
$numberOfRetries = [int]::Parse("${{ parameters.numberOfRetries }}")
if ($numberOfRetries -eq -1) {
$numberOfRetries = [int]::MaxValue
}
$retryCounter = $numberOfRetries
$lastFailure = [DateTime]::MinValue
# Call provided expression and retry on failure
while ($true) {
try {
$expression = "${{ parameters.expression }}"
Write-Host "##[command]Invoke-Expression -Command `"& $expression`""
Invoke-Expression -Command "& $expression"
break # normal exit
}
catch {
# if multiple failures within the given time
$currentFailure = [DateTime]::Now
if ($currentFailure -lt $lastFailure.AddMinutes([int]::Parse("${{ parameters.recentFailureThresholdInMinutes }}"))) {
# update failure count and retry counter
$failureCount++
$retryCounter--
} else {
# reset failure count and retry counter
$failureCount = 0
$retryCounter = $numberOfRetries
}
if ($retryCounter -gt 0) {
# wait before trying again
$retryWaitTime = [Math]::Min([Math]::Pow($failureCount, 2), [int]::Parse("${{ parameters.maxRetryWaitTimeInMinutes }}") * 60)
Write-Host "##vso[task.logissue type=warning]$($currentFailure.ToString('HH:mm:ssK')) | Keep calm and carry on... [Last failure = $($lastFailure.ToString('HH:mm:ssK')) | Recent failures = $failureCount | Wait time = $retryWaitTime | Attempt = $($numberOfRetries - $retryCounter + 1)] :: $_"
Start-Sleep -Seconds $retryWaitTime
}
else {
throw $_
}
$succeedWithIssues = $true
$lastFailure = $currentFailure
}
}
# Exit with warning if any failures
if ($succeedWithIssues) {
Write-Host "##vso[task.complete result=SucceededWithIssues;]DONE"
exit 0
}
displayName: ${{ parameters.displayName }}
workingDirectory: $(Build.SourcesDirectory)
retryCountOnTaskFailure: ${{ parameters.retryCountOnTaskFailure }}
env: ${{ parameters.env }}