Recent searches
No recent searches
App request has been throttled
Posted Mar 30, 2023
Hi,
I'm trying to address an issue with my app which I submitted to the app store, but has blockers. The final blocker is to do with rate limiting. I was given the following instruction:
- We ask that you include a backoff and proper 429 error messaging for rate limiting. You should implement a custom back off strategy in an exponential fashion (1s, 2s, 5s, 10s, 30s, 5 min intervals).
I have first implemented an error trap for 429 errors. It looks like this:
myURL = "retry"
while(myURL = "retry"){
myURL = await client.request(settings).then(
function(data) {
// DO STUFF
},
async function(response) {
if (response.status === 429) {
const retryAfter = response.headers.get('retry-after')
console.log("429 error")
await sleep(retryAfter)
return "retry"
}
else
{
// DO SOMETHING ELSE
}
},
);
}
I was hoping that this approach would make it unnecessary to implement the exponential back off -- as after the 429 error, it would wait the appropriate amount of time before retrying the API. When testing this I have found that no 429 errors are occurring (or at least no message is going to the console). But I am getting this warning to the console:
... app request has been throttled: /api/v2/search.json?query=...etc
First, would I still need the exponential back-off strategy if I am using the 'wait until', as above.
Second, can anyone explain why I am getting throttling messages but no 429 error.
Help is appreciated.
Thanks.
0
7 comments
Greg Katechis
Hi Simon!
To answer your first question, you could utilize the retry-after strategy that you implemented above, however I believe that the reason we have the exponential back-off recommendation is in the event that the API does not include that header. From what I can recall, there was a point where we may not have always included that and it's also possible that a new API or a change could briefly miss it. To that end, it might be a safe bet to include the back-off as well, but if that feels too cumbersome, I would submit the app without it as that feels sufficient. That decision isn't up to my team though, so you may be told something different.
Regarding the second issue, it's possible that you were throttled by ZAF instead of the API, although that probably should have sent a 429 as well. Does this happen consistently or was it just the one time?
0
SGL
Hi Greg Katechis,
Thanks for your reply. I think I will submit the code without the back-off strategy and see if it is accepted.
For the throttling message, I get this every time that I do a test involving many calls to the API. It works fine for a while (presumably because the threshold hasn't been passed) but then I get the throttling messages adding up.
I tried adding "autoRetry: false," option to the request, but I still get the throttling warnings.
I've tried running it in development mode (zat=true) and also installing it on Zendesk, but the results are the same for both.
Thanks.
0
Greg Katechis
To that end, I'd like to see your implementation of the request just in case there's something funny in the options. If you wouldn't mind passing along the settings you're using for that (and the rest of the block as well), I'll be glad to look into this!
0
SGL
Hi Greg Katechis,
Sorry, I didn't see your reply until now.
Here is the function that shows the throttling warnings in the console (note that it never reaches the 429 error code):
// ------ Get the IDs of open tickets for users in the list -----
async function getOpenTicketsForUsers(){
userTicketIDs = [];
// loop users and find unclosed tickets for user
for(u=0;u<userIDs.length;u++){
userID = userIDs[u];
API = "/api/v2/search.json?query=status<closed requester:" + userID;
myURL = encodeURI(API);
pageCounter = 1;
while(!(myURL===null)) // loop through until no 'next page'
{
var settings = {
url: myURL,
type:'GET',
dataType: 'json',
autoRetry: false,
};
// NEW for rate limiting purposes
myURL = "retry"
while(myURL = "retry"){
myURL = await client.request(settings).then(
function(data) {
tempIDs = [];
txt = getJSONInfo2(data);
nextURL = txt.next_page;
openTickets = txt.results;
recordCount = txt.count; //parseInt(txt.count);
if(recordCount>100)
{
if(nextURL===null)
{
recordCount = recordCount % 100;
}
else
{
recordCount = 100;
}
}
for (t = 0; t < recordCount; t++) {
tempIDs.push(openTickets[t].id);
}
userTicketIDs = userTicketIDs.concat(tempIDs);
return nextURL;
},
async function(response) {
showError(response);
// NEW -- catch 429 error
if (response.status === 429) {
const retryAfter = response.headers.get('retry-after')
console.log("retry 1")
await sleep(retryAfter)
return "retry"
}
else
{
console.log("null 1")
return null
}
},
);
}
}
}
return userTicketIDs;
}
0
SGL
Hi Greg Katechis
Have you managed to look at my throttling issue yet?
Thanks,
Simon.
0
Paulo Filho
Hi Greg Katechis
Have you managed to look at throttling issue yet?
I have a very similar problem, I would like to see the answer of this thread.
Thanks,
0
SGL
Hi Greg Katechis
C.C. Paulo Filho
I've done some load testing on the API, which produced many 'throttling' warning messages, but no 429 errors in the main (I did get a single one at one point, but couldn't reproduce). I feel the throttling is something beyond my control to catch in the code, so I think that the 429 error trap is the best I can do.
I have also modified the error trap (I think either the syntax was wrong for returning the "retry-after" value, or it may not return this for all API calls). The new error trap implements an exponential back-off strategy. Here is a snippet of the code:
if (response.status === 429) {
retryAfter = 1000 * Math.pow(2, W);
W = W + 1; //exponential increase in wait time.
await sleep(retryAfter)
return "retry"
}
I should note that I seem to be getting fewer throttling messages in my app since making changes, but this may or may not be due to other factors. Under certain circumstances I may get as many as previously (?).
As far as I'm concerned, we can close this thread. I'm going to mark this post as 'answer'.
Thanks, Simon.
1