Retry-After is never read on 429 retries: dict(httpx.Headers) lowercases the key
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 78/100
Línea de trabajo
Empieza por shopify_app/graphql/admin_graphql.py en las líneas 111 y 708; después, inspecciona los handlers 429 sync y async de las líneas 389 y 445. Reproduce el comportamiento de las claves de encabezado con el fragmento de httpx proporcionado y confirma que ambas rutas de reintento usan el valor Retry-After proporcionado por el servidor en lugar del valor predeterminado.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
In admin_graphql_request, the Retry-After header is never read on a 429 response. The lookup always falls through to its "1" default, so every rate-limit retry sleeps exactly one second regardless of what the server asked for.
Affects both the sync and async paths.
Version: shopifyapp 1.0.1 (sdist from PyPI), httpx 0.28.1.
Cause
shopify_app/graphql/admin_graphql.py:111 (and :708 on the async path) normalizes the response headers with:
response_headers = dict(response.headers)
dict() on an httpx.Headers instance produces lowercased keys. The 429 handlers then look the header up with its canonical casing, at shopify_app/graphql/admin_graphql.py:389 (sync) and :445 (async):
retry_after = response_headers.get("Retry-After", "1")
That key is never present, so retry_after is always the literal string "1".
Reproduction
import httpx
h = httpx.Headers({"Retry-After": "2.0", "Content-Type": "application/json"})
d = dict(h)
print(list(d)) # ['retry-after', 'content-type']
print(d.get("Retry-After", "1")) # '1' <- expected '2.0'
Impact
The client ignores server-provided backoff on rate limiting and retries on a fixed one-second interval instead. With the default max_retries=2 that is about two seconds of total backoff, typically well short of what a rate-limited endpoint asks for.
Suggested fix
httpx.Headers is already case-insensitive, so reading from the response object directly avoids the problem:
retry_after = response.headers.get("Retry-After", "1")
Keeping the dict and looking up the lowercase key works too.
One caveat: fixing this lookup on its own exposes a second defect on the same value, where int(retry_after) raises ValueError on anything that is not a bare integer. Filed separately as #18, which also notes that the two are best addressed together.
- Lenguaje dominante
- Python
- Estrellas
- 17
- Forks
- 1
- Merge medio
- 4 min
- PR fusionados (30 d)
- 1
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Shopify/shopify-app-python
-
devtools-gardener
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Todos los issues de Shopify/shopify-app-python
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
raullenchai/Rapid-MLX#4042 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
LearningCircuit/local-deep-research#7067 ·
Los mantenedores suelen responder en 1 día
-
#bug
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
apache/superset#44923 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
lawndoc/stack-back#123 ·