feat: Handle rate limit errors by respecting X-RateLimit-Reset and Retry-After headers and returning cached queue length#7684
Conversation
…g cached queue length Signed-off-by: andrewhibbert <[email protected]>
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Thank you for your contribution! 🙏 Please understand that we will do our best to review your PR and give you feedback as soon as possible, but please bear with us if it takes a little longer as expected. While you are waiting, make sure to:
Once the initial tests are successful, a KEDA member will ensure that the e2e tests are run. Once the e2e tests have been successfully completed, the PR may be merged at a later date. Please be patient. Learn more about our contribution guide. |
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
|
/run-e2e github* |
| s.logger.V(1).Info(fmt.Sprintf( | ||
| "Github API rate limit exceeded. Cached queue length: %d, last checked at %s", | ||
| s.previousQueueLength, | ||
| s.previousQueueLengthTime, | ||
| )) |
There was a problem hiding this comment.
One thing I was wondering about, when we fall back to the cached queue length, the only signal to the operator is a V(1) log line. Could we also create an event? That way tools like Argo CD would pick it up and show it on the resource directly, which feels like a much better fit here. Not every user has access to the KEDA operator logs (or knows to look there), and I think this is actually an important signal. Without it, unexpected scaling behaviour can be hard to explain. Wdyt?
(As a smaller secondary thing, it might
be worth bumping the V(1) log to V(0) so there's continuous visibility in the logs while we're rate-limited, not just at the transition. But the event is the main thing.)
There was a problem hiding this comment.
could the log be spammy? IDK how often this happens so maybe it's too much? (I have 0 idea, just asking) the event is 100% worth it ❤️
| func (s *githubRunnerScaler) getRateLimit(header http.Header) (RateLimit, error) { | ||
| var retryAfterTime time.Time | ||
|
|
||
| remainingStr := header.Get("X-RateLimit-Remaining") |
There was a problem hiding this comment.
is this header always set? Do we need to check if it's present before trying to cast it?
| return RateLimit{}, fmt.Errorf("failed to parse X-RateLimit-Remaining header: %w", err) | ||
| } | ||
|
|
||
| resetStr := header.Get("X-RateLimit-Reset") |
There was a problem hiding this comment.
is this header always set? Do we need to check if it's present before trying to cast it?
| s.logger.V(1).Info(fmt.Sprintf( | ||
| "Github API rate limit exceeded. Cached queue length: %d, last checked at %s", | ||
| s.previousQueueLength, | ||
| s.previousQueueLengthTime, | ||
| )) |
There was a problem hiding this comment.
could the log be spammy? IDK how often this happens so maybe it's too much? (I have 0 idea, just asking) the event is 100% worth it ❤️
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
|
Thanks for adding the event! The event fires on every reconcile while we're rate-limited. That could be a lot of events, because the message includes "last checked at ", so each event is unique, so Kubernetes' event aggregation won't dedupe them. Would it be worth only emitting on state transitions? So once when we go into Further, does |
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
The "last checked at " is the last time it last cached inside GetWorkflowQueueLength, so once rate limited this time won't change. I have changed the event to be EventTypeNormal and removed the no cache event |
|
Thanks for the explanation. But a separate thing I hadn't spotted before: is "last checked at" correct or is a bit misleading? Would something like "last successful cache at" be more accurate? |
…try-After headers and returning cached queue length Signed-off-by: andrewhibbert <[email protected]>
Agreed, I have changed it to "last successful cache at" |
|
/run-e2e github* |
|
/run-e2e github* |
|
/run-e2e github* |
|
loooooool. merging kedacore/keda-docs#1749 I've closed directly this one 🤦 |
Provide a description of what has been changed
Checklist
make generate-scalers-schemahas been run to update any outdated generated filesFixes #7683
Relates to: kedacore/keda-docs#1749
Follow on from #7192 and comment #7192 (review)