Skip to content

Commit 6c6b6ae

Browse files
committed
Adjust curl timeouts, retries and logging
In #1439, the timeouts used with curl were set to higher values than we needed for Heroku's build system, in order to prevent timeouts in non-Heroku environments such as Dokku running on underpowered devices (or devices with poor internet connections). However, as seen in recent Honeycomb metrics, these higher timeouts cause longer delays on Heroku before a curl retry if there is a transient S3 connection issue - since the request will wait the full 10 seconds `connect_timeout` before retrying. As such, the defaults have been lowered again to be optimised for running on Heroku, and support for overriding the defaults via env var added to still allow running in other environments. Specifically: - The default connection timeout has been lowered from 10 seconds to 3, but can now be overridden via the env var `CURL_CONNECT_TIMEOUT` - The default total request timeout has been lowered from 120 seconds to 60, but can be overridden via `CURL_TIMEOUT` These env vars cannot be set via Heroku config vars, and must instead be set in the build system environment (or by an earlier buildpack). The env var names match those used by the classic Ruby buildpack: https://github.com/heroku/heroku-buildpack-ruby/blob/a6d124492aafe7f7ee0dd42d7a79284b6552d675/lib/language_pack/fetcher.rb#L47-L53 In addition, the usages of `--silent --show-error` have been replaced with `--no-progress-meter`, which is otherwise identical apart from it allowing warnings to be shown, such as the status messages output during retry attempts (of form: "Will retry in 1 seconds. 3 retries left" etc). Before: ``` -----> Installing Python 3.13.7 curl: (6) Could not resolve host: heroku-buildpack-python.s3.us-east-1.amazonaws.com curl: (6) Could not resolve host: heroku-buildpack-python.s3.us-east-1.amazonaws.com ... ``` After: ``` -----> Installing Python 3.13.7 curl: (7) Failed to connect to heroku-buildpack-python.s3.us-east-1.amazonaws.com port 443 after 3 ms: Couldn't connect to server Warning: Problem : connection refused. Will retry in 1 seconds. 5 retries left. curl: (7) Failed to connect to heroku-buildpack-python.s3.us-east-1.amazonaws.com port 443 after 4 ms: Couldn't connect to server Warning: Problem : connection refused. Will retry in 2 seconds. 4 retries left. ... ``` Lastly, the maximum number of retries has been increased slightly. Note: The curl options used in `build_python_runtime.sh` have also been adjusted, however, since these are only used by buildpack maintainers (typically by running them on GitHub Actions), there is no need to those timeouts configurable. GUS-W-19414036.
1 parent 30086f2 commit 6c6b6ae

File tree

4 files changed

+32
-26
lines changed

4 files changed

+32
-26
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
## [Unreleased]
44

55
- Updated uv from 0.8.9 to 0.8.13. ([#1880](https://github.com/heroku/heroku-buildpack-python/pull/1880))
6+
- Reduced default curl timeouts for faster retries of any transient connection issues on Heroku. ([#1884](https://github.com/heroku/heroku-buildpack-python/pull/1884))
7+
- Added support for overriding the default curl timeouts using `CURL_CONNECT_TIMEOUT` and `CURL_TIMEOUT`. These are intended for use in non-Heroku environments with slow connections, and so must be set via the build system rather than app config vars. ([#1884](https://github.com/heroku/heroku-buildpack-python/pull/1884))
8+
- Improved log output during curl retry attempts. ([#1884](https://github.com/heroku/heroku-buildpack-python/pull/1884))
69
- Switched to Bash 5.0's `EPOCHREALTIME` for buildpack data store timing logic. ([#1881](https://github.com/heroku/heroku-buildpack-python/pull/1881))
710

811
## [v302] - 2025-08-21

builds/build_python_runtime.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#!/usr/bin/env bash
22

3+
# This script is used by buildpack maintainers to compile new Python versions as they are released,
4+
# ready for upload to S3. (It isn't run as part of normal buildpack execution during app builds.)
5+
# See `builds/README.md` for how to invoke this via GitHub Actions.
6+
37
set -euo pipefail
48
shopt -s inherit_errexit
59

@@ -71,8 +75,8 @@ set -o xtrace
7175

7276
mkdir -p "${SRC_DIR}" "${INSTALL_DIR}" "${UPLOAD_DIR}"
7377

74-
curl --fail --retry 3 --retry-connrefused --connect-timeout 10 --max-time 60 -o python.tgz "${SOURCE_URL}"
75-
curl --fail --retry 3 --retry-connrefused --connect-timeout 10 --max-time 60 -o python.tgz.asc "${SIGNATURE_URL}"
78+
curl --fail --retry 5 --retry-connrefused --connect-timeout 3 --max-time 30 -o python.tgz "${SOURCE_URL}"
79+
curl --fail --retry 5 --retry-connrefused --connect-timeout 3 --max-time 30 -o python.tgz.asc "${SIGNATURE_URL}"
7680

7781
gpg --batch --verbose --recv-keys "${GPG_KEY_FINGERPRINT}"
7882
gpg --batch --verify python.tgz.asc python.tgz

lib/python.sh

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,20 @@ function python::install() {
3737
# shellcheck disable=SC2310 # This function is invoked in an 'if' condition so set -e will be disabled.
3838
if ! {
3939
{
40-
# We set max-time for improved UX/metrics for hanging downloads compared to relying
41-
# on the build system timeout. The Python archives are only ~10 MB so take < 1s to
42-
# download on Heroku's build system, however, we use much higher timeouts so that
43-
# the buildpack works in non-Heroku environments that may be far from `us-east-1`
44-
# or have a slower connection. We don't use `--speed-limit` since it gives worse
45-
# error messages when used with retries and piping to tar.
40+
# We set max-time for improved UX/metrics for hanging downloads compared to relying on the build
41+
# system timeout. We don't use `--speed-limit` since it gives worse error messages when used with
42+
# retries and piping to tar. The Python archives are ~10 MB so only take ~1s to download on Heroku,
43+
# so set low timeouts to reduce delays before retries. However, we allow customising the timeouts
44+
# to support non-Heroku environments that may be far from `us-east-1` or have a slower connection.
45+
# We use `--no-progress-meter` rather than `--silent` so that retry status messages are printed.
4646
curl \
47-
--connect-timeout 10 \
47+
--connect-timeout "${CURL_CONNECT_TIMEOUT:-3}" \
4848
--fail \
49-
--max-time 120 \
50-
--retry-max-time 120 \
51-
--retry 3 \
49+
--max-time "${CURL_TIMEOUT:-60}" \
50+
--no-progress-meter \
51+
--retry-max-time "${CURL_TIMEOUT:-60}" \
52+
--retry 5 \
5253
--retry-connrefused \
53-
--show-error \
54-
--silent \
5554
"${python_url}" \
5655
| tar \
5756
--directory "${install_dir}" \

lib/uv.sh

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,22 @@ function uv::install_uv() {
3030
local uv_url="https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${gnu_arch}-unknown-linux-gnu.tar.gz"
3131

3232
if ! {
33-
# We set max-time for improved UX for hanging downloads compared to relying on the build system
34-
# timeout. The uv archive is only ~15 MB so takes < 1s to download on Heroku's build system,
35-
# however, we use much higher timeouts so that the buildpack works in non-Heroku or local
36-
# environments that may have a slower connection. We don't use `--speed-limit` since it gives
37-
# worse error messages when used with retries and piping to tar.
38-
# We have to use `--strip-components` since the archive contents are nested under a subdirectory.
33+
# We set max-time for improved UX/metrics for hanging downloads compared to relying on the build
34+
# system timeout. We don't use `--speed-limit` since it gives worse error messages when used with
35+
# retries and piping to tar. The Python archives are ~10 MB so only take ~1s to download on Heroku,
36+
# so set low timeouts to reduce delays before retries. However, we allow customising the timeouts
37+
# to support non-Heroku environments that may be far from `us-east-1` or have a slower connection.
38+
# We use `--no-progress-meter` rather than `--silent` so that retry status messages are printed.
39+
# We have to use `--strip-components` since the uv binary is nested under a subdirectory.
3940
curl \
40-
--connect-timeout 10 \
41+
--connect-timeout "${CURL_CONNECT_TIMEOUT:-3}" \
4142
--fail \
4243
--location \
43-
--max-time 120 \
44-
--retry-max-time 120 \
45-
--retry 3 \
44+
--max-time "${CURL_TIMEOUT:-60}" \
45+
--no-progress-meter \
46+
--retry-max-time "${CURL_TIMEOUT:-60}" \
47+
--retry 5 \
4648
--retry-connrefused \
47-
--show-error \
48-
--silent \
4949
"${uv_url}" \
5050
| tar \
5151
--directory "${uv_dir}" \

0 commit comments

Comments
 (0)