Handle null returns from search cache methods

This commit is contained in:
James Agnew 2019-10-15 16:19:38 -04:00
parent 9c23959b38
commit bf476b9c32
4 changed files with 90 additions and 10 deletions

View File

@ -209,11 +209,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
search = mySearchCacheSvc
.fetchByUuid(theUuid)
.orElseThrow(() -> {
ourLog.trace("Client requested unknown paging ID[{}]", theUuid);
String msg = myContext.getLocalizer().getMessage(PageMethodBinding.class, "unknownSearchId", theUuid);
return new ResourceGoneException(msg);
});
.orElseThrow(() -> newResourceGoneException(theUuid));
verifySearchHasntFailedOrThrowInternalErrorException(search);
if (search.getStatus() == SearchStatusEnum.FINISHED) {
@ -252,12 +248,22 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
ourLog.trace("Finished looping");
List<Long> pids = mySearchResultCacheSvc.fetchResultPids(search, theFrom, theTo);
if (pids == null) {
throw newResourceGoneException(theUuid);
}
ourLog.trace("Fetched {} results", pids.size());
return pids;
}
@Nonnull
private ResourceGoneException newResourceGoneException(String theUuid) {
ourLog.trace("Client requested unknown paging ID[{}]", theUuid);
String msg = myContext.getLocalizer().getMessage(PageMethodBinding.class, "unknownSearchId", theUuid);
return new ResourceGoneException(msg);
}
private void populateBundleProvider(PersistedJpaBundleProvider theRetVal) {
theRetVal.setContext(myContext);
@ -1101,14 +1107,21 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
txTemplate.afterPropertiesSet();
txTemplate.execute(t -> {
List<Long> previouslyAddedResourcePids = mySearchResultCacheSvc.fetchAllResultPids(getSearch());
if (previouslyAddedResourcePids == null) {
throw newResourceGoneException(getSearch().getUuid());
}
ourLog.debug("Have {} previously added IDs in search: {}", previouslyAddedResourcePids.size(), getSearch().getUuid());
setPreviouslyAddedResourcePids(previouslyAddedResourcePids);
return null;
});
} catch (Throwable e) {
ourLog.error("Failure processing search", e);
getSearch().setFailureMessage(e.toString());
getSearch().setFailureMessage(e.getMessage());
getSearch().setStatus(SearchStatusEnum.FAILED);
if (e instanceof BaseServerResponseException) {
getSearch().setFailureCode(((BaseServerResponseException) e).getStatusCode());
}
saveSearch();
return null;

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.search.cache;
import ca.uhn.fhir.jpa.entity.Search;
import javax.annotation.Nullable;
import java.util.List;
public interface ISearchResultCacheSvc {
@ -38,14 +39,20 @@ public interface ISearchResultCacheSvc {
* @param theSearch The search to fetch IDs for
* @param theFrom The starting index (inclusive)
* @param theTo The ending index (exclusive)
* @return A list of resource PIDs
* @return A list of resource PIDs, or <code>null</code> if the results no longer exist (this should only happen if the results
* have been removed from the cache for some reason, such as expiry or manual purge)
*/
@Nullable
List<Long> fetchResultPids(Search theSearch, int theFrom, int theTo);
/**
* Fetch all result PIDs for a given search with no particular order required
* @param theSearch
* @return
*
* @param theSearch The search object
* @return A list of resource PIDs, or <code>null</code> if the results no longer exist (this should only happen if the results
* have been removed from the cache for some reason, such as expiry or manual purge)
*/
@Nullable
List<Long> fetchAllResultPids(Search theSearch);
}

View File

@ -469,6 +469,62 @@ public class SearchCoordinatorSvcImplTest {
assertEquals("109", resources.get(99).getIdElement().getValueAsString());
}
/**
* Simulate results being removed from the search result cache but not the search cache
*/
@Test
public void testFetchResultsReturnsNull() {
Search search = new Search();
search.setStatus(SearchStatusEnum.FINISHED);
search.setNumFound(100);
search.setTotalCount(100);
when(mySearchCacheSvc.fetchByUuid(eq("0000-1111"))).thenReturn(Optional.of(search));
when(mySearchResultCacheSvc.fetchResultPids(any(), anyInt(), anyInt())).thenReturn(null);
try {
mySvc.getResources("0000-1111", 0, 10, null);
fail();
} catch (ResourceGoneException e) {
assertEquals("Search ID \"0000-1111\" does not exist and may have expired", e.getMessage());
}
}
/**
* Simulate results being removed from the search result cache but not the search cache
*/
@Test
public void testFetchAllResultsReturnsNull() {
when(myDaoRegistry.getResourceDao(anyString())).thenReturn(myCallingDao);
when(myCallingDao.getContext()).thenReturn(ourCtx);
Search search = new Search();
search.setUuid("0000-1111");
search.setResourceType("Patient");
search.setStatus(SearchStatusEnum.PASSCMPLET);
search.setNumFound(5);
search.setSearchParameterMap(new SearchParameterMap());
when(mySearchCacheSvc.fetchByUuid(eq("0000-1111"))).thenReturn(Optional.of(search));
when(mySearchCacheSvc.tryToMarkSearchAsInProgress(any())).thenAnswer(t->{
search.setStatus(SearchStatusEnum.LOADING);
return Optional.of(search);
});
when(mySearchResultCacheSvc.fetchAllResultPids(any())).thenReturn(null);
try {
mySvc.getResources("0000-1111", 0, 10, null);
fail();
} catch (ResourceGoneException e) {
assertEquals("Search ID \"0000-1111\" does not exist and may have expired", e.getMessage());
}
}
public static class FailAfterNIterator extends BaseIterator<Long> implements IResultIterator {
private int myCount;

View File

@ -39,6 +39,10 @@ public enum SearchStatusEnum {
/**
* The search failed and will not continue
*/
FAILED
FAILED,
/**
* The search has been expired and will be expunged shortly
*/
GONE
}