Skip to content

Instantly share code, notes, and snippets.

@vector623
Last active February 10, 2018 02:26
Show Gist options
  • Save vector623/9f087f253653f1dd08ed793f1c7ec26f to your computer and use it in GitHub Desktop.
Save vector623/9f087f253653f1dd08ed793f1c7ec26f to your computer and use it in GitHub Desktop.
AggregateUntil() example
public static List<Label> GetLabels()
{
/*
* use linq's lazy loading feature to enumerate an unlimited number of page requests. so i created AggregateUntil() to
* take in a Func() which will inform when to stop iterating - in this case, we want to stop after the entries count
* exceeds the totalNumEntries value, which Google Adwords returns from the first query
*/
var labels = Enumerable
.Range(0, Int32.MaxValue) //range generates a list of integers, from 1 to practically infinity
.AggregateUntil(
new LabelPage()
{
entries = new Label[] { },
totalNumEntries = 0,
},
(accumulatedLabelPage, pageIndex) =>
{
/*
* also use select() and first() to mitigate rate limiting; setup 5 identical requests and while the
* returned page is null (meaning there was a caught exception), keep retrying. after first() stops
* the evaluation, or you've attempted up to the max number of times to fetch, there will be one
* non-empty page result. if there is no result at all, Single() will throw an error, which is what we
* want to happen
*/
var thisLabelsPage = Enumerable
.Range(0, pageMaxFetchAttempts)
.Select(pageAttempt =>
{
// this is the exponential backoff
Thread.Sleep(2500 * pageAttempt * pageAttempt);
try
{
var labelsAwql =
$"select LabelId,LabelName,LabelStatus limit {(pageIndex * pageSize)},{pageSize}";
var attemptedlabelsPage = Config.SupplyLabelService.query(labelsAwql);
return attemptedlabelsPage;
}
catch (Exception e)
{
return new LabelPage();
}
})
.First(page => page != null);
return new LabelPage()
{
entries = accumulatedLabelPage
.entries
.ToList()
.Concat(thisLabelsPage.entries)
.ToArray(),
totalNumEntries = thisLabelsPage.totalNumEntries,
totalNumEntriesSpecified = thisLabelsPage.totalNumEntriesSpecified,
PageType = thisLabelsPage.PageType,
};
},
(accumulatedLabelPage) =>
{
var shouldStop = accumulatedLabelPage.entries.Length >= accumulatedLabelPage.totalNumEntries;
return shouldStop;
})
.entries
.ToList();
return labels;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment