-
Notifications
You must be signed in to change notification settings - Fork 260
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
Feed back API rate limits requests to the application. Demonstrate how to handle rate limit exceptions with Guzzle Middleware #897
Conversation
Set the maximum wait time on retrying send requests.
IF Xero return a 429 api limit response, get the retry time from the response, and check if it is less than the configured maximum wait time limit. If it is, then wait and retry the request.
Passing requests rate limits back allows the bundle to decide if it should slow down API calls.
@mogilvie just reading through this–I'm wondering if this is the correct place to be handling the throttling. I can see that you've got to be intentional with that config parameter, but potentially just sleeping in execution of the request could lead to some potentially undesirable timeouts, especially as the rest of the application will have no idea that it's caught/sleeping for that reason. Is there a way we could move that handling out of the middle of the request while keeping it simple? For instance, you could inject a middleware into the Guzzle constructor and leverage the "retry" middleware? See https://github.com/guzzle/guzzle/blob/7.7/src/RetryMiddleware.php |
Thanks @calcinai, wasn't aware of the middleware option. I'll do that. |
So, looking further, we can achieve the retry using the current Application::setTransport, where the parent bundle can construct a Client with the the RetryMiddleware in the HanderStack. Shall I just document this, instead of modifying the Application? Or should I add a method for that replaces the Client Transport with a RetryMiddleware constructed one? |
Pass bool in constructor to skip creating a client if setting transport
Have updated PR to allow user to skip the default guzzle client, and provide their own Client as a transport. |
@mogilvie Yeah that's what I was getting at! Sorry I didn't quite get here until you'd already written the code.. |
I think I'm done. Review at your leisure. |
@mogilvie I think this way is much cleaner, thanks for your work. The only thing I think would improve would be to either extend or duplicate the guzzle middleware to catch the errors and increment those counters. It'd also remove the need to do all the plumbing in user/app space. Functionally I think it's great as is, so this would really just shuffling some code around. Thoughts? |
There are three feature aspects to be considered here.
The call count status is available in the normal response headers from the Xero API. Item 2 is just a way of exposing those to the application. Should we be looking at a different method of doing that? Any preference? |
Cool, well let's stick with how it is. The thing that got me thinking about it was really just the |
I could change that getAppRateLimits() array response to individual getters? |
@mogilvie If you don't mind, I think that would be great. Really appreciate the back and forward on this. |
Return limits remaining as individual getters
swapped out getAppRateLimits for individual getters. |
PR for issue #806
Pass the API Request Rate Limits back up to the Application to allow the user of the bundle to decide if they throttle api requests.
Have also added an option to throttle requests from within the bundle itself.
Set a configurable variable in the Application, which sets the maximum wait time that the application should delay if it hits an API limit. (Can be set false if no intention to retry requests)
Catch Xero 429 Response issues where the API limit has been reached.
Get the 'Retry-After' time from the Xero response header.
If the Retry-After period is less than the permitted maximum duration in the config, then sleep for the retry period, and retry the request.