| 769 | return float(retry_date - time.time()) |
| 770 | |
| 771 | def _calculate_retry_timeout( |
| 772 | self, |
| 773 | remaining_retries: int, |
| 774 | options: FinalRequestOptions, |
| 775 | response_headers: Optional[httpx.Headers] = None, |
| 776 | ) -> float: |
| 777 | max_retries = options.get_max_retries(self.max_retries) |
| 778 | |
| 779 | # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. |
| 780 | retry_after = self._parse_retry_after_header(response_headers) |
| 781 | if retry_after is not None and 0 < retry_after <= 60: |
| 782 | return retry_after |
| 783 | |
| 784 | # Also cap retry count to 1000 to avoid any potential overflows with `pow` |
| 785 | nb_retries = min(max_retries - remaining_retries, 1000) |
| 786 | |
| 787 | # Apply exponential backoff, but not more than the max. |
| 788 | sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) |
| 789 | |
| 790 | # Apply some jitter, plus-or-minus half a second. |
| 791 | jitter = 1 - 0.25 * random() |
| 792 | timeout = sleep_seconds * jitter |
| 793 | return timeout if timeout >= 0 else 0 |
| 794 | |
| 795 | def _should_retry(self, response: httpx.Response) -> bool: |
| 796 | # Note: this is not a standard header |