You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4e6ebae
Browse filesBrowse the repository at this point in the historyBrowse files
echo "Anonymous ECR Public pulls are throttled per source IP and GitHub runners share theirs."
227
+
exit 0
228
+
fi
229
+
if ! command -v aws >/dev/null 2>&1; then
230
+
echo "::error::AWS credentials are set but the aws CLI is missing"; exit 1
231
+
fi
232
+
# ECR Public only exists in us-east-1; the token is valid for 12 h,
233
+
# long enough for the whole job. A failed login is not fatal: the
234
+
# pre-pull step then falls back to anonymous pulls and reports
235
+
# whatever actually goes wrong there.
236
+
if ! aws ecr-public get-login-password --region us-east-1 \
237
+
| docker login --username AWS --password-stdin public.ecr.aws; then
238
+
echo "::warning::ECR Public login failed - the credentials are invalid or lack ecr-public:GetAuthorizationToken. Falling back to anonymous pulls, which are rate limited per source IP."
239
+
fi
240
+
241
+
# Pull every task image before Pier starts, for two reasons:
242
+
# * a throttled pull then fails the run in minutes with a readable
243
+
# message instead of surfacing as a docker-compose stack trace in
244
+
# the middle of the benchmark;
245
+
# * the retry loop below actually gets to run - Pier reports a failed
246
+
# image pull as a failed trial and does not retry it.
247
+
# The set of images is resolved through Pier's own DatasetConfig, so it
248
+
# is exactly what `pier run --n-tasks ... --sample-seed ...` will use.
249
+
- name: Pre-pull task images
250
+
env:
251
+
N_TASKS: ${{ inputs.n_tasks }}
252
+
run: |
253
+
set -euo pipefail
254
+
# workflow_dispatch supplies the default, but a dispatch via the API
255
+
# can omit inputs entirely; never call the resolver with an empty arg.
256
+
n_tasks="${N_TASKS:-10}"
257
+
# Assign first: a command substitution's exit status inside a process
258
+
# substitution is discarded, and a resolver failure would then show up
259
+
# as the much less useful "no task image resolved".
echo "::error::Could not resolve the task images for n_tasks=${n_tasks} (see the traceback above)"; exit 1
265
+
fi
266
+
if [ -z "$resolved" ]; then
267
+
echo "::error::No task image resolved from deep-swe/tasks"; exit 1
268
+
fi
269
+
mapfile -t rows <<< "$resolved"
270
+
echo "Resolved ${#rows[@]} task(s) for n_tasks=${n_tasks}"
271
+
272
+
pull() {
273
+
local image="$1" attempt=1 delay=15
274
+
until docker pull --quiet "$image"; do
275
+
if [ "$attempt" -ge 5 ]; then
276
+
echo "::warning::docker pull ${image} failed after ${attempt} attempts"
277
+
return 1
278
+
fi
279
+
echo "::warning::docker pull ${image} failed (attempt ${attempt}); retrying in ${delay}s"
280
+
sleep "$delay"
281
+
attempt=$((attempt + 1))
282
+
delay=$((delay * 2))
283
+
done
284
+
}
285
+
286
+
declare -A seen
287
+
pulled=0
288
+
total=${#rows[@]}
289
+
failed=0
290
+
# Room kept free for the trials themselves (each builds a child image
291
+
# and writes logs and verifier artifacts).
292
+
reserve_mb=4096
293
+
for row in "${rows[@]}"; do
294
+
image="${row#*$'\t'}"
295
+
if [ -n "${seen[$image]:-}" ]; then continue; fi
296
+
seen[$image]=1
297
+
298
+
# Different tasks' images share most layers, so N tasks cost far
299
+
# less than N x an image: the 10-task sample is 3.2 GB compressed
300
+
# (~7 GB unpacked) and the runner has ~14 GB. Stop here rather than
301
+
# letting a trial die on `no space left on device`.
302
+
avail=$(df -Pm / | awk 'NR==2 {print $4}')
303
+
if [ "$avail" -lt "$reserve_mb" ]; then
304
+
echo "::error::Only ${avail} MiB of disk left after ${pulled}/${total} image(s): this runner cannot hold the images plus the trials. Request fewer tasks (1-2 give a meaningful score) or use a larger runner."
305
+
exit 1
306
+
fi
307
+
308
+
if ! pull "$image"; then
309
+
failed=$((failed + 1))
310
+
# The anonymous quota does not recover inside one job, so stop
311
+
# rather than spending four more minutes on every other image.
312
+
break
313
+
fi
314
+
pulled=$((pulled + 1))
315
+
done
316
+
317
+
if [ "$failed" -ne 0 ]; then
318
+
echo "::error::${failed} task image(s) could not be pulled from public.ecr.aws."
319
+
echo "Most likely ECR Public throttled the anonymous pull: it meters per source IP and GitHub runners share theirs."
320
+
echo "Fix: add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY secrets (any AWS account with ecr-public:GetAuthorizationToken and sts:GetServiceBearerToken) so pulls are authenticated, or re-run this job so it lands on another runner."
321
+
echo "If the log shows 'no space left on device', the runner's disk is the limit: request fewer tasks."
322
+
exit 1
323
+
fi
324
+
echo "All task images are present locally."
325
+
326
+
# The egress-proxy container builds FROM ubuntu:24.04 (Docker Hub),
327
+
# which is rate limited too, though far less aggressively.
328
+
# Best effort: a failure here is not fatal.
329
+
docker pull --quiet ubuntu:24.04 \
330
+
|| echo "::warning::Could not pre-pull ubuntu:24.04"
331
+
332
+
# Space left for the trials themselves.
333
+
df -h / | tail -n 1
334
+
avail=$(df -Pm / | awk 'NR==2 {print $4}')
335
+
if [ "$avail" -lt "$reserve_mb" ]; then
336
+
echo "::warning::Only ${avail} MiB free after pre-pulling. Trials may fail with 'no space left on device'; use fewer tasks or a larger runner."
0 commit comments