Retry-After is never read on 429 retries: dict(httpx.Headers) lowercases the key

未关闭 适合新手
#17 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
78/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
python
领域
api, backend

调研方向

从 shopify_app/graphql/admin_graphql.py 的第 111 行和第 708 行开始,然后检查第 389 行和第 445 行的 sync 和 async 429 处理器。使用提供的 httpx 代码片段复现 header-key 行为,并确认两条重试路径都使用服务器提供的 Retry-After 值,而不是默认值。

由索引模型根据 Issue 内容生成。

描述

devtools-gardener

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.

主要语言
Python
星标
17
派生
1
平均合并
3 分钟
30 天内合并 PR
2

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Shopify/shopify-app-python 的其他 Issue

查看 Shopify/shopify-app-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。