-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lfs: add support for rate limit retries #340
Conversation
28ace21
to
42f0798
Compare
@sisp, does this honor |
@skshetry Do you mean the |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #340 +/- ##
==========================================
- Coverage 77.50% 77.38% -0.12%
==========================================
Files 39 39
Lines 5068 5081 +13
Branches 909 915 +6
==========================================
+ Hits 3928 3932 +4
- Misses 985 994 +9
Partials 155 155 ☔ View full report in Codecov by Sentry. |
I am not sure if it is the same as one we pass to scmrepo/src/scmrepo/git/lfs/client.py Line 41 in 42f0798
What happens if a request gets |
Ah, now I see what you mean. If a request gets |
That's great. The only concern that I have with this PR is that a malicious server could return a large value, that might lead the user to believe So I am not sure if this should be the default, or should be enabled via some config. |
How does |
According to the Git LFS config documentation:
It sounds to me as if rate limit retries can't be disabled. But I'm not able to prove it using the official Git LFS implementation. Although I consider it unlikely, I understand your concern. How about applying the same maximum timeout from class _ExponentialRetry(ExponentialRetry):
def get_timeout(
self, attempt: int, response: Optional[aiohttp.ClientResponse] = None
) -> float:
if response is not None and response.status == HTTPStatus.TOO_MANY_REQUESTS:
+ timeout: Optional[float] = None
if "Retry-After" in response.headers:
with suppress(ValueError):
- return float(response.headers["Retry-After"])
- for k in ["RateLimit-Reset", "X-RateLimit-Reset"]:
- if k in response.headers:
- with suppress(ValueError):
- return float(response.headers[k]) - time()
+ timeout = float(response.headers["Retry-After"])
+ else:
+ for k in ["RateLimit-Reset", "X-RateLimit-Reset"]:
+ if k in response.headers:
+ with suppress(ValueError):
+ timeout = float(response.headers[k]) - time()
+ break
+ if timeout is not None:
+ return min(timeout, self._max_timeout)
return super().get_timeout(attempt, response) |
@pmrowla, if you have any thoughts? 👋🏽 |
We do assume that the remotes are trusted by the users, so that may not be a big issue as I am making. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, a few questions to clarify. Thanks @sisp !
Can we also add some tests for this please?
@shcheklein There aren't any integration tests against an LFS test server yet, so testing rate limit retries would mean significant test setup work first. I'd defer this to follow-up PRs. WDYT? |
@sisp yes, absolutely, I didn't mean proper integration tests. Primarily was thinking about unit tests with mocks in this case - to make sure that just cover this new Retry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your call on unit tests. Thanks @sisp !
I'll look into adding unit tests tomorrow. |
@sisp you also should be able to merge PRs now (I've added you as collaborator to the project). |
Wow, thanks, I appreciate your trust. 🙏 |
I've added support for handling rate limit responses and retrying requests accordingly.
Typical rate limit responses use the status code 429 and include one of the following headers:
Retry-After: <delay in seconds>
is used by, e.g., GitLabRateLimit-Reset: <timestamp>
is used by, e.g., GitLabX-RateLimit-Reset: <timestamp>
is used by, e.g., GitHubThe implementation is inspired by the corresponding implementation in the
python-gitlab
library and based on the GitHub documentation on rate limits.