Resolve 5112 unable to expunge deleted codesystem until several minutes later (#5113)

* returned user-friendlier message, implemented unit tests, added changelog

* reformatted file

* added Msg.code to the exception thrown

* added Msg.code in test

* Changed to catch DataIntegrityViolationException only.
This commit is contained in:
TynerGjs 2023-07-21 13:08:58 -04:00 committed by GitHub
parent d31da211b9
commit f68f3fbb0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 8 deletions

View File

@ -0,0 +1,4 @@
---
type: fix
issue: 5112
title: "Returns better diagnostics message to expunge requests that failed due to unfinished batch deletion"

View File

@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.dao.expunge;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut;
@ -51,6 +52,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.MemoryCacheService;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
import org.apache.commons.lang3.Validate;
@ -59,6 +61,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
@ -315,16 +318,22 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
deleteAllSearchParams(JpaPid.fromId(resource.getResourceId()));
if (resource.isHasTags()) {
myResourceTagDao.deleteByResourceId(resource.getId());
}
try {
if (resource.isHasTags()) {
myResourceTagDao.deleteByResourceId(resource.getId());
}
if (resource.getForcedId() != null) {
ForcedId forcedId = resource.getForcedId();
myForcedIdDao.deleteByPid(forcedId.getId());
}
if (resource.getForcedId() != null) {
ForcedId forcedId = resource.getForcedId();
myForcedIdDao.deleteByPid(forcedId.getId());
}
myResourceTableDao.deleteByPid(resource.getId());
myResourceTableDao.deleteByPid(resource.getId());
} catch (DataIntegrityViolationException e) {
throw new PreconditionFailedException(Msg.code(2415)
+ "The resource could not be expunged. It is likely due to unfinished asynchronous deletions, please try again later: "
+ e);
}
}
@Override

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
@ -68,6 +69,7 @@ import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -119,6 +121,15 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
}
}
private void assertNotExpunged(IIdType theId) {
try {
getDao(theId).read(theId);
fail();
} catch (ResourceGoneException e) {
// good
}
}
private void assertStillThere(IIdType theId) {
getDao(theId).read(theId);
}
@ -888,6 +899,28 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
runInTransaction(this::verifyCodeSystemsAndChildrenExpunged);
}
@Test
public void testDeleteCodeSystemByUrlThenExpungeWithoutWaitingForBatch() {
//set up
createStandardCodeSystems();
myCodeSystemDao.deleteByUrl("CodeSystem?url=" + URL_MY_CODE_SYSTEM, null);
myTerminologyDeferredStorageSvc.saveDeferred();
try {
// execute
myCodeSystemDao.expunge(new ExpungeOptions()
.setExpungeDeletedResources(true)
.setExpungeOldVersions(true), null);
fail("expunge should not succeed since the delete batch job is not complete");
} catch (InternalErrorException e){
// verify
assertNotExpunged(myOneVersionCodeSystemId.withVersion("2"));
assertThat(e.getMessage(), startsWith(
"HAPI-1084: ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException: HAPI-2415: The resource could not be ex" +
"punged. It is likely due to unfinished asynchronous deletions, please try again later:"));
}
}
private List<Patient> createPatientsWithForcedIds(int theNumPatients) {
RequestDetails requestDetails = new SystemRequestDetails();
List<Patient> createdPatients = new ArrayList<>();