private async Task <(IEnumerable <Match> matches, bool moreMatchesAvailable)> GetMatchesInCommonPageAsync(string guid, string guidInCommon, int pageNumber, bool throwException, Throttle throttle) { if (guid == guidInCommon) { return(Enumerable.Empty <Match>(), false); } var nameUnavailableCount = 0; var nameUnavailableMax = 60; var retryCount = 0; var retryMax = 5; while (true) { await throttle.WaitAsync(); var throttleReleased = false; try { using (var testsResponse = await _ancestryLoginHelper.AncestryClient.GetAsync($"discoveryui-matchesservice/api/samples/{guid}/matches/list?page={pageNumber}&relationguid={guidInCommon}&bookmarkdata={{\"moreMatchesAvailable\":true,\"lastMatchesServicePageIdx\":{pageNumber - 1}}}")) { throttle.Release(); throttleReleased = true; if (testsResponse.StatusCode == System.Net.HttpStatusCode.Gone) { return(Enumerable.Empty <Match>(), false); } if (testsResponse.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable) { await Task.Delay(120000); continue; } testsResponse.EnsureSuccessStatusCode(); var matches = await testsResponse.Content.ReadAsAsync <MatchesV2>(); var matchesInCommon = matches.MatchGroups.SelectMany(matchGroup => matchGroup.Matches) .Select(match => new Match { MatchTestAdminDisplayName = match.AdminDisplayName, MatchTestDisplayName = match.DisplayName, TestGuid = match.TestGuid, SharedCentimorgans = match.Relationship?.SharedCentimorgans ?? 0, SharedSegments = match.Relationship?.SharedSegments ?? 0, Starred = match.Starred, Note = match.Note, }) .ToList(); if (matchesInCommon.Any(match => match.Name == "name unavailable") && ++nameUnavailableCount < nameUnavailableMax) { await Task.Delay(3000); continue; } return(matchesInCommon, matches.BookmarkData.MoreMatchesAvailable); } } catch (Exception ex) { if (++retryCount >= retryMax) { FileUtils.LogException(ex, true); await Task.Delay(ex is UnsupportedMediaTypeException? 30000 : 3000); if (throwException) { throw; } return(Enumerable.Empty <Match>(), false); } await Task.Delay(ex is UnsupportedMediaTypeException? 30000 : 3000); } finally { if (!throttleReleased) { throttle.Release(); } } } }
public async Task <IEnumerable <Match> > GetMatchesPageAsync(string guid, HashSet <int> tagIds, int pageNumber, bool includeAdditionalInfo, Throttle throttle, ProgressData progressData) { var nameUnavailableCount = 0; var nameUnavailableMax = 60; var retryCount = 0; var retryMax = 5; while (true) { await throttle.WaitAsync(); var throttleReleased = false; try { using (var testsResponse = await _ancestryLoginHelper.AncestryClient.GetAsync($"discoveryui-matchesservice/api/samples/{guid}/matches/list?page={pageNumber}&bookmarkdata={{\"moreMatchesAvailable\":true,\"lastMatchesServicePageIdx\":{pageNumber - 1}}}")) { throttle.Release(); throttleReleased = true; testsResponse.EnsureSuccessStatusCode(); var matches = await testsResponse.Content.ReadAsAsync <MatchesV2>(); var result = matches.MatchGroups.SelectMany(matchGroup => matchGroup.Matches) .Select(match => ConvertMatch(match, tagIds)) .ToList(); // Sometimes Ancestry returns matches with partial data. // If that happens, retry and hope to get full data the next time. if (result.Any(match => match.Name == "name unavailable") && ++nameUnavailableCount < nameUnavailableMax) { await Task.Delay(3000); continue; } progressData.Increment(); if (includeAdditionalInfo) { try { await GetAdditionalInfoAsync(guid, result, throttle); } catch { // non-fatal if unable to download trees } if (pageNumber == 1) { try { await GetParentsAsync(guid, result, throttle); } catch { // non-fatal if unable to download parents } } } progressData.Increment(); return(result); } } catch (Exception ex) { if (++retryCount >= retryMax) { FileUtils.LogException(ex, true); await Task.Delay(ex is UnsupportedMediaTypeException? 30000 : 3000); return(Enumerable.Empty <Match>()); } await Task.Delay(ex is UnsupportedMediaTypeException? 30000 : 3000); } finally { if (!throttleReleased) { throttle.Release(); } } } }