An error was recently pointed out on one of the extension that I’ve been working on as part of the ALM Rangers.
Looking at the browser logs we noticed something like this:
"An undefined error occurred while attempting to connect to the server. Status code 0: error."
Very descriptive, right?!
It turns out that the root of the error lies in the fact that we were hitting limits with regards to work item queries. It looks like VSTS/TFS API only allows us to "read" in the region of about 300 work items at a go. It appears that there are teams out there that need up to a few thousand at a go.
How did I fix this? A great little JavaScript library called Q.
It was a fairly simple change as we all use the promise pattern for asynchronous calls to the services. Q is a chaining library that allows me to create a bunch of promises and wait for them to complete execution.
Practically this means breaking the list of work item id’s that I need into smaller chunks and then fetching these chunks. We could have simply written a recursive loop that would perform the same, but I’m lazy.
The code change looked like this:
From simply calling the API with all the work item id’s:
client.getWorkItems(backlogIds, null, asOfDate, WorkItemContracts.WorkItemExpand.Relations).then(backlogWorkItems => {
//process
defer.resolve(result);
});
To:
var loadSpecs = new Array<IPromise<any>>();
var spliceSize = 100;
var backlogSection = backlog.splice(0, spliceSize);
while (backlogSection.length > 0) {
loadSpecs.push(this.GetWorkItemDetails(backlogSection, asOfDate));
var backlogSection = backlog.splice(0, spliceSize);
}
Q.all(loadSpecs).done(all => {
//combine “all” the results into one
defer.resolve(result);
});
The GetWorkItemDetails method simple returns the promise from client.getWorkItems:
public GetWorkItemDetails(backlogItems: number[], asOf: Date): IPromise<any> {
var client = WorkItemRestClient.getClient();
var defer = $.Deferred<any>();
client.getWorkItems(backlogItems, null, asOf,
WorkItemContracts.WorkItemExpand.Relations)
.then(backlogWorkItems =>
{
//process
defer.resolve(result);
});
return defer;
}
This may not be the neatest, and please do not criticize my Javascript skills (I’m not a JS developer ), but it works and was a lot quicker to “fix” than expected.
For the full source code feel free to go and have a look at the github repo, in fact why not join in and make it better !