55name : Download artifact (with retry)
66
77description : >-
8- Wrapper around actions/download-artifact that retries once after a short
9- delay when the first attempt fails. Designed to absorb transient
10- infrastructure flakes such as "other side closed" without failing the job.
8+ Wrapper around actions/download-artifact that retries up to three times with
9+ exponential backoff when a download fails. Handles both transient TCP errors
10+ such as "other side closed" and storage-layer throttling such as
11+ "HTTP 503: Egress is over the account limit". Accepts either an exact
12+ artifact name or a glob pattern; supply exactly one.
1113
1214inputs :
1315 name :
14- description : " Name of the artifact to download"
15- required : true
16+ description : >-
17+ Exact name of the artifact to download. Mutually exclusive with
18+ 'pattern'; supply exactly one of the two.
19+ required : false
20+ default : " "
21+ pattern :
22+ description : >-
23+ Glob pattern matching one or more artifact names. Mutually exclusive
24+ with 'name'; supply exactly one of the two.
25+ required : false
26+ default : " "
27+ merge-multiple :
28+ description : >-
29+ When true and 'pattern' is set, merge files from all matched artifacts
30+ directly into 'path' instead of placing each in its own subdirectory.
31+ required : false
32+ default : " false"
1633 path :
17- description : " Destination path for the downloaded artifact"
34+ description : " Destination path for the downloaded artifact(s) "
1835 required : true
1936 run-id :
2037 description : >-
@@ -32,39 +49,80 @@ inputs:
3249 required : false
3350 default : " "
3451 retry-delay-seconds :
35- description : " Seconds to wait between the first failure and the retry "
52+ description : " Seconds to wait between the first failure and the second attempt "
3653 required : false
3754 default : " 15"
3855
3956runs :
4057 using : composite
4158 steps :
59+ - name : Validate inputs
60+ shell : bash --noprofile --norc -euo pipefail {0}
61+ env :
62+ INPUT_NAME : ${{ inputs.name }}
63+ INPUT_PATTERN : ${{ inputs.pattern }}
64+ run : |
65+ if [[ -n "${INPUT_NAME}" && -n "${INPUT_PATTERN}" ]]; then
66+ echo "::error::Specify exactly one of 'name' or 'pattern', not both"
67+ exit 1
68+ fi
69+ if [[ -z "${INPUT_NAME}" && -z "${INPUT_PATTERN}" ]]; then
70+ echo "::error::Specify exactly one of 'name' or 'pattern'"
71+ exit 1
72+ fi
73+
4274 - name : Download artifact (attempt 1)
4375 id : attempt1
4476 continue-on-error : true
4577 uses : actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
4678 with :
4779 name : ${{ inputs.name }}
80+ pattern : ${{ inputs.pattern }}
81+ merge-multiple : ${{ inputs.merge-multiple }}
4882 path : ${{ inputs.path }}
4983 run-id : ${{ inputs.run-id }}
5084 github-token : ${{ inputs.github-token }}
5185
52- - name : Wait before retry
86+ - name : Wait before retry (attempt 2)
5387 if : ${{ steps.attempt1.outcome == 'failure' }}
5488 shell : bash --noprofile --norc -euo pipefail {0}
5589 env :
56- # Pass through env instead of interpolating the input into the shell
57- # script, so a non-numeric value cannot inject commands.
5890 RETRY_DELAY_SECONDS : ${{ inputs.retry-delay-seconds }}
5991 run : |
6092 echo "::warning::Artifact download failed (attempt 1); retrying in ${RETRY_DELAY_SECONDS}s"
6193 sleep "$RETRY_DELAY_SECONDS"
6294
6395 - name : Download artifact (attempt 2)
96+ id : attempt2
6497 if : ${{ steps.attempt1.outcome == 'failure' }}
98+ continue-on-error : true
99+ uses : actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
100+ with :
101+ name : ${{ inputs.name }}
102+ pattern : ${{ inputs.pattern }}
103+ merge-multiple : ${{ inputs.merge-multiple }}
104+ path : ${{ inputs.path }}
105+ run-id : ${{ inputs.run-id }}
106+ github-token : ${{ inputs.github-token }}
107+
108+ - name : Wait before retry (attempt 3)
109+ if : ${{ steps.attempt1.outcome == 'failure' && steps.attempt2.outcome == 'failure' }}
110+ shell : bash --noprofile --norc -euo pipefail {0}
111+ env :
112+ RETRY_DELAY_SECONDS : ${{ inputs.retry-delay-seconds }}
113+ run : |
114+ # Double the delay for the second retry to give egress throttling more time to clear.
115+ RETRY_DELAY_SECONDS=$(( RETRY_DELAY_SECONDS * 2 ))
116+ echo "::warning::Artifact download failed (attempt 2); retrying in ${RETRY_DELAY_SECONDS}s"
117+ sleep "$RETRY_DELAY_SECONDS"
118+
119+ - name : Download artifact (attempt 3)
120+ if : ${{ steps.attempt1.outcome == 'failure' && steps.attempt2.outcome == 'failure' }}
65121 uses : actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
66122 with :
67123 name : ${{ inputs.name }}
124+ pattern : ${{ inputs.pattern }}
125+ merge-multiple : ${{ inputs.merge-multiple }}
68126 path : ${{ inputs.path }}
69127 run-id : ${{ inputs.run-id }}
70128 github-token : ${{ inputs.github-token }}
0 commit comments