-
Notifications
You must be signed in to change notification settings - Fork 737
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
Adjust GHRateLimit to system time instead of depending on synchronization #595
Conversation
Improves the way reset date is calculated - uses server date if possible. Fixes hub4j#383
647f06d
to
a6f2360
Compare
a6f2360
to
9c80b7c
Compare
Cool! I will take a look at it during lunchtime :) |
Sometimes adding tests finds broken product code. Sometimes it finds broken test environment. This was the latter. The wiremock templating returns dates in UTC format not RFC-1123 format.
303960e
to
37de3a4
Compare
Introduces hub4j#597 This does not appear to be a bug in github-api but in OkHttp 2.7.5 (and/or the Cache implementation in that version).
Hi @bitwiseman,
Good catch! That is a nice way of fixing the problem. 👍 [Re: refactoring/improvements you made] Currently, we're using the In case you want to go down that road, the |
|| headerRateLimit.getResetDate().getTime() < observed.getResetDate().getTime() | ||
|| headerRateLimit.remaining > observed.remaining) { | ||
|| headerRateLimit.getRemaining() > observed.getRemaining() | ||
|| headerRateLimit.getResetEpochSeconds() < observed.getResetEpochSeconds()) { |
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.
I must be missing something really simple but... I took a look at the git history and the issues used to discuss the original implementation (back in 2017) and I still don't get why we wouldn't update the headerRateLimit
variable every time updateRateLimit
method is invoked.
Would you mind sharing with me your understanding of that if statement and/or any idea of when this would be applicable?
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.
Hm, good question. Ah, I remember now. Multi-threading.
If you have 10 threads all make queries and then all try to update the rate limit. We want to pick the one with the lowest remaining count, of if a reset occurs we want to pick the one with the later reset date.
I need to write a test that covers this and add comments to the code explaining.
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.
ahhhhh, that makes sense :)
@PauloMigAlmeida |
@PauloMigAlmeida |
I agree with you, all of that seems a bit too much for a single PR. If you don't mind, after you finish this refactor I would love to try implementing the newer rate limits myself. That should be fun 😄 On the other hand, if you want to implement it, please count on me for reviewing it too |
426abda
to
0d0b687
Compare
} else { | ||
// records of the same type compare to each other as normal. | ||
return current.getResetEpochSeconds() < candidate.getResetEpochSeconds() | ||
|| (current.getResetEpochSeconds() == candidate.getResetEpochSeconds() && current.getRemaining() > candidate.getRemaining()); |
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.
@PauloMigAlmeida
This is the check that your question got me to fix.
A recorder with a later reset is for sure newer that one with an earlier one.
Only if they have the same reset should we take the one with the lower remaining count.
Previous implementation would take the lower remaining count candidate even if it had an earlier (older) reset date.
Thanks!
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.
It makes sense! I like the train of thought you used for solving it.
@PauloMigAlmeida |
Created GHRateLimit.Record Add the four rate limit records to GHRateLimit Moved getLimt(), getRemaining(), and so on to point to core record for ease of use. Fixed update check for header to not replace existing with older when remaining count is lower. NOTE: Did not expose records other than core and did not resolve header update behavior to respect non-core records.
0d0b687
to
03e9623
Compare
@PauloMigAlmeida How does this look to you now? |
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 great! Can't wait to see it on the next version of the library 😃
} else { | ||
// records of the same type compare to each other as normal. | ||
return current.getResetEpochSeconds() < candidate.getResetEpochSeconds() | ||
|| (current.getResetEpochSeconds() == candidate.getResetEpochSeconds() && current.getRemaining() > candidate.getRemaining()); |
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.
It makes sense! I like the train of thought you used for solving it.
Fixes #383
Related to #591
@martinvanzijl @PauloMigAlmeida
if you have a little time to look at this over, any feedback would be appreciated.
Summary
If the client time is out of sync with global time, GHRateLimit could report a
resetDate
that was completely wrong - accurate to global time, but disconnected from local system time. This wouldn't be so bad, but some clients use theresetDate
to budget API calls. If they believe they have 10 hours until reset and only 4000 calls available, they effective lock up.Further, public fields and having a "Date" field that is holding unconverted EpochSeconds just bothers me.
I deprecated the old public fields and added private fields with getters. I then added awareness of the Date header returned with the Http response. Using that we can generate
calculatedSecondsUntilReset
and the create theresetDate
by adding that to System-time that his instance was created.As a final step, I made it so
rateLimit()
will update automatically when then GHRateLimit instance expires.