Different results with multiple AP.request calls

I’ve been able to work through most of my own issues regarding making multiple AP.request calls due to maxResult limits Atlassian has on certain calls. Here’s my scenario:

  • Retrieving Screen Schemes which has a maxResult of 25–this cannot be changed.
  • My test instance has (60) total screen schemes, so I have to make (3) AP.request calls.
  • Each call, I update the startAt value to grab the next dataset until it has grabbed everything.
  • This works, but if I sometime I get all (60). Other times I get (10). Other times I get (35).
  • Each call should be (25), (25) and (10) for a total of (60).
  • Basically I get all results, some results or the last results.

I believe the random results is because of the async nature of AP.request. I saw some very cluttered methods on Google but I think the takeaway is I should be using Promise to ensure each call has successfully completed before moving on to drawing the datatable.

This is the last fix I need to complete the rollout of the next version of my Atlassian app. If anyone is aware of a good post, whether in this community or elsewhere, regarding properly ensuring the AP.request calls have all completed I would appreciate it!

I’ll continue to look myself, but hoping that being pointed in the right direction will save me some time. Thanks in advance!

I can’t be sure specifically, but it does sound like you’re hitting a race condition with the async calls, especially if you’re updating the startAt value each time.

The documentation for AP.request gives an example for how to use Promises here. Make sure you’re executing the next AP.request call after the previous one has succeeded.

Yes, I’ve been using that page and a couple of others as a guide.

Where I am now: If I remove the code to draw my DataTable, it appears that I get all of the calls I am looking for (I have executed this new code ~15 times and each time I get all of the data back. I print out "data’ each time and it is displaying the results from each call. I am merging each result into “finalJson” and at the end of execution “finalJson” contains an object for each call (an Object of Objects). So my goal is to use “finalJson” to build my DataTable as it contains all of the data.

Results: When I add the code to draw the DataTable inside the success block, I get varying results (this code is not include below). Which I understand because sometimes it is drawing the table before the request has grabbed all of the data. But if I try to access “finalJson” after the requests calls are done, then I’m getting an empty object (result is [] 0 or something like that).

Here is my code block thus far (please forgive any sloppiness as this is not the final code, just code I am using for testing purpose to achieve the desired results).

total: in this environment it is currently (60).
maxResults: set by Atlassian is (25).
screenschemeTable: do not worry about this one for now.

// This is a test function as I work to get the desired results.
function getAllSchemes(total, maxResults, screenschemeTable) {
// Using these to help build the final JSON results.
var mergedJson = [];
var finalJson = [];

console.log("We are here");

// Loop to increment startAt to grab all data in the instance.
for (startIndex = 0; startIndex < total; startIndex+=maxResults) {
    //console.log ("Index: " + startIndex);
    
    // This may not be correct as I took it from an Atlassian Community thread.
    new Promise((resolve, reject) => {

        AP.request('/rest/api/3/screenscheme?startAt=' + startIndex, {
            success: function(responseText) {
                resolve(responseText);
                //console.log("Succcessful!");
                //console.log("Response: " + responseText);
                
                // Each pass through I am building the finalJson object.
                var data = JSON.parse(responseText);
                mergedJson.push(data);
                finalJson = $.extend(true, {}, finalJson, mergedJson);

                console.log("Data: ", data);
                console.log("Final: ", finalJson);
            }, // End of success block.
            error: function(xhr, statusText, errorThrown) {
                reject(arguements);
                console.log("Errors");
                //console.log("Reject: ", reject(arguments);
            } // End of error block.
        }) // End of Request block.
    }); // End of Promise block.
} // End of for loop block.

console.log("We are done");

} // End of Function.

I know the DataTable code needs to wait until I have the finalJson object. Due to getting undesired results by putting this code into the success: block, I’m pretty sure it should not go there, but if that is true, how to I retain finalJson outside of the request block?

Thanks in advance for straightening me out as this is my first Atlassian App. Everything works like a charm otherwise, but I will need to update a few areas like this one to ensure I am getting all data due to the Atlassian imposed maxResults.

My apologies as I forgot to attach a screenshot of the output. As you can see, finalJson is the result of each request. So that part is working correctly

Ok, I found the issue “finally”! The code I’ve been writing was always returning all of the data. Where I was going wrong was using the isLast key to try and determine when it was time to draw the DataTable.

A brief explanation in case it will help someone else. I was making the requests and assuming it was grabbing the chunks of data like this first 25 rows, second 25 rows, and the remaining 10 rows. With the 10 batch having isLast = true.

However, the calls were being done in any order so 10 was not always the last call. For example, the calls could return the data chunks in 10, 25, 25 or 25, 10, 25, etc. and the isLast = true that I was looking for was not always appearing on the last call.

In short, the last call was not always what I thought it was and isLast was not always appearing on what I thought was the last call. Therefore, I used another, more reliable mechanism to check and determine if I was on the last call:

Basically using currentIndex+maxResult > dataTotal. If this is true, then I know I am on the last call and can safely return the Object of Objects I build during each call.

Thanks @huw for pointing me towards some information that helped me resolve the issue!

1 Like