<p>正如MRA所说,您不应该试图回避一个<code>429 Too Many Requests</code>,而应该相应地处理它。根据您的用例,您有几个选项:</p>
<p>1)<strong>睡眠您的过程</strong>。服务器通常在响应中包含一个<code>Retry-after</code>头,其中包含您在重试之前应该等待的秒数。请记住,睡眠进程可能会导致问题,例如在任务队列中,您应该稍后重试该任务,以释放工作进程的其他资源。</p>
<p>2)<strong><a href="https://en.wikipedia.org/wiki/Exponential_backoff" rel="noreferrer">Exponential backoff</a></strong>。如果服务器不告诉您等待多长时间,您可以使用中间不断增加的暂停来重试请求。受欢迎的任务队列芹菜具有此功能<a href="http://docs.celeryproject.org/en/latest/userguide/tasks.html#Task.retry_backoff" rel="noreferrer">built right-in</a>。</p>
<p>3)<strong><a href="https://en.wikipedia.org/wiki/Token_bucket" rel="noreferrer">Token bucket</a></strong>。如果事先知道在给定时间内可以发出多少请求,则此技术非常有用。每次访问API时,首先从bucket中获取一个令牌。桶是以恒定的速率重新装满的。如果bucket是空的,您知道在再次命中API之前必须等待。令牌桶通常在另一端(API)实现,但也可以将它们用作代理,以避免获得<code>429 Too Many Requests</code>。芹菜的<a href="http://docs.celeryproject.org/en/latest/userguide/tasks.html#Task.rate_limit" rel="noreferrer">rate_limit</a>功能使用令牌桶算法。</p>
<p>下面是一个使用指数退避和速率限制/令牌桶的Python/芹菜应用程序示例:</p>
<pre><code>class TooManyRequests(Exception):
"""Too many requests"""
@task(
rate_limit='10/s',
autoretry_for=(ConnectTimeout, TooManyRequests,),
retry_backoff=True)
def api(*args, **kwargs):
r = requests.get('placeholder-external-api')
if r.status_code == 429:
raise TooManyRequests()
</code></pre>