【问题标题】:How to handle with rate limiting with requests_futures?如何处理 requests_futures 的速率限制?
【发布时间】:2020-02-03 22:25:48
【问题描述】:

我一直在使用 Python 请求从 API 获取数据,但我想通过使用 requests_futures 异步运行来加速它。我每分钟只允许 200 个 API 请求,所以我必须检查这一点并等待指定的秒数,然后再重试。此数字在 Retry-After 标头中返回。这是原始工作代码:

  session = requests.Session()
  for id in ticketIds:
    url = 'https://colorfront.zendesk.com/api/v2/tickets/' + str(id) + '/comments.json'
    req = requests.get(url, auth=zd_secret)

    if req.status_code == 429:
      time.sleep(int(req.headers['Retry-After']))
      req = requests.get(url, auth=zd_secret)

    comments += req.json()['comments']

以下异步代码在达到速率限制之前一直工作,然后所有请求都失败。

session = FuturesSession()
  futures = {}
  for id in ticketIds:
    url = 'https://colorfront.zendesk.com/api/v2/tickets/' + str(id) + '/comments.json'
    futures[id] = session.get(url, auth=zd_secret)

  for id in ticketIds:
    comments += futures[id].result().json()['comments']

当我达到速率限制时,我需要一种方法来仅重试失败的请求。 requests_futures 是否有一些内置的方法来处理这个问题?

更新:requests_futures 库没有为此内置任何内容。我发现了这个相关的未解决问题:https://github.com/ross/requests-futures/issues/26。因为我知道 API 限制,所以我会尝试提前调整请求的速度,但是如果我的组织中的另一个用户同时访问同一个 API,这将无济于事。

【问题讨论】:

    标签: python rest python-requests


    【解决方案1】:

    您应该可以使用urllib3.util.retry 中的重试模块来实现此目的:

    from requests_futures.sessions import FuturesSession
    from requests.adapters import HTTPAdapter
    from urllib3.util.retry import Retry
    
    session = FuturesSession()
    retries = 5
    status_forcelist = [429]
    retry = Retry(
         total=retries,
         read=retries,
         connect=retries,
         respect_retry_after_header=True,
         status_forcelist=status_forcelist,
    )
    
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    
    futures = {}
    for id in ticketIds:
        url = 'https://colorfront.zendesk.com/api/v2/tickets/' + str(id) + '/comments.json'
        futures[id] = session.get(url, auth=zd_secret)
    
    for id in ticketIds:
        comments += futures[id].result().json()['comments']
    

    【讨论】:

    • 此方法是否检查Retry-After 标头?
    • 您可以使用以下选项配置重试模块:respect_retry_after_header=True。检查我的答案中的链接以获取其他配置选项。
    • 谢谢,这听起来是个不错的解决方案。我正在研究一种不同的方法,所以我也将其发布为答案。不确定哪种方式更好。
    【解决方案2】:

    我想我已经找到了解决办法。我不知道这是否是最好的方法,但它避免了另一种依赖。我可以同时处理max_workersx 请求,以根据这家咖啡店的互联网速度优化效率。

    session = FuturesSession(max_workers=2)
    futures = {}
    res = {}
    delay = 0
    x = 200
    while ticketIds:
      time.sleep(delay)
      if len(ticketIds) > x - 1:
        for id in ticketIds[:x]:
          url = 'https://colorfront.zendesk.com/api/v2/tickets/' + str(id) + '/comments.json'
          futures[id] = session.get(url, auth=zd_secret)
      else:
        for id in ticketIds:
          url = 'https://colorfront.zendesk.com/api/v2/tickets/' + str(id) + '/comments.json'
          futures[id] = session.get(url, auth=zd_secret)
    
      # use a copy of the list
      for id in ticketIds[:]:
        if id in futures:
          res[id] = futures[id].result()
          # remove successful IDs from list
          if res[id].status_code == 200:
            ticketIds.remove(id)
            comments += res[id].json()['comments']
          else:
            delay = int(res[id].headers['Retry-After'])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-13
      • 1970-01-01
      • 2018-08-07
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-06
      相关资源
      最近更新 更多