Compare commits

...

11 Commits

Author SHA1 Message Date
jdar8 e06f573ebf
Merge a2457abd58 into 3f6d1eb29b 2024-09-26 02:08:10 +00:00
Thomas Papke 3f6d1eb29b
#5768 Upgrade to latest simple-java-mail (#6261) 2024-09-26 02:07:27 +00:00
Tadgh 377e44b6ca
attribution and pom change (#6309) 2024-09-25 20:38:22 +00:00
jdar a2457abd58 Merge branch 'master' into jd-20240812-add-detail-delete-expunge-log-messages 2024-09-03 10:43:26 -07:00
jdar b1eb4ca046 spotless 2024-08-26 10:27:56 -07:00
jdar 72a837cb10 pass the whole work chunk instead of just the ID 2024-08-26 10:21:43 -07:00
jdar 6772b2160f change string check 2024-08-21 11:21:11 -07:00
jdar b727f635df spotless and remove comments 2024-08-12 16:09:28 -07:00
jdar a7c53e444f changes 2024-08-12 16:06:05 -07:00
jdar c9424c5948 changes 2024-08-12 16:01:06 -07:00
jdar 5917317c17 test 2024-08-12 15:50:40 -07:00
20 changed files with 184 additions and 78 deletions

View File

@ -0,0 +1,5 @@
---
type: add
issue: 6210
jira: SMILE-8428
title: "The batch chunk ID has been added to the delete expunge log messages to make troubleshooting easier."

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 6290
title: "Previously, a specific migration task was using the `TRIM()` function, which does not exist in MSSQL 2012. This was causing migrations targeting MSSQL 2012 to fail.
This has been corrected and replaced with usage of a combination of LTRIM() and RTRIM(). Thanks to Primož Delopst at Better for the contribution!"

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.dao.expunge.ResourceTableFKProvider;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import graphql.VisibleForTesting;
import jakarta.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -56,8 +57,9 @@ public class DeleteExpungeSqlBuilder {
myResourceLinkDao = theResourceLinkDao;
}
@VisibleForTesting
@Nonnull
DeleteExpungeSqlResult convertPidsToDeleteExpungeSql(
public DeleteExpungeSqlResult convertPidsToDeleteExpungeSql(
List<JpaPid> theJpaPids, boolean theCascade, Integer theCascadeMaxRounds) {
Set<Long> pids = JpaPid.toLongSet(theJpaPids);

View File

@ -19,10 +19,12 @@
*/
package ca.uhn.fhir.jpa.delete.batch2;
import ca.uhn.fhir.batch2.model.WorkChunk;
import ca.uhn.fhir.jpa.api.svc.IDeleteExpungeSvc;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.model.dao.JpaPid;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.model.api.IModelJson;
import jakarta.persistence.EntityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -48,19 +50,26 @@ public class DeleteExpungeSvcImpl implements IDeleteExpungeSvc<JpaPid> {
}
@Override
public int deleteExpunge(List<JpaPid> theJpaPids, boolean theCascade, Integer theCascadeMaxRounds) {
public <PT extends IModelJson> int deleteExpunge(
List<JpaPid> theJpaPids, boolean theCascade, Integer theCascadeMaxRounds, PT theWorkChunk) {
DeleteExpungeSqlBuilder.DeleteExpungeSqlResult sqlResult =
myDeleteExpungeSqlBuilder.convertPidsToDeleteExpungeSql(theJpaPids, theCascade, theCascadeMaxRounds);
List<String> sqlList = sqlResult.getSqlStatements();
ourLog.debug("Executing {} delete expunge sql commands", sqlList.size());
String formattedChunkIdForLogMessage = "";
if (theWorkChunk instanceof WorkChunk
&& !((WorkChunk) theWorkChunk).getId().isBlank()) {
formattedChunkIdForLogMessage = "Chunk[" + ((WorkChunk) theWorkChunk).getId() + "] - ";
}
ourLog.debug("{}Executing {} delete expunge sql commands", formattedChunkIdForLogMessage, sqlList.size());
long totalDeleted = 0;
for (String sql : sqlList) {
ourLog.trace("Executing sql " + sql);
totalDeleted += myEntityManager.createNativeQuery(sql).executeUpdate();
}
ourLog.info("{} records deleted", totalDeleted);
ourLog.info("{}Delete expunge sql commands affected {} rows", formattedChunkIdForLogMessage, totalDeleted);
clearHibernateSearchIndex(theJpaPids);
// TODO KHS instead of logging progress, produce result chunks that get aggregated into a delete expunge report

View File

@ -70,6 +70,11 @@
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<optional>true</optional>
</dependency>
<!-- test dependencies -->
<dependency>

View File

@ -28,8 +28,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

View File

@ -17,8 +17,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;

View File

@ -26,8 +26,8 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.beans.factory.annotation.Autowired;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

View File

@ -1408,7 +1408,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
final List<JpaPid> pidOrThrowException1 = List.of(pidOrThrowException);
final TransactionTemplate transactionTemplate = new TransactionTemplate(getTxManager());
transactionTemplate.execute(x -> myDeleteExpungeSvc.deleteExpunge(pidOrThrowException1, true, 10));
transactionTemplate.execute(x -> myDeleteExpungeSvc.deleteExpunge(pidOrThrowException1, true, 10, null));
}
}

View File

@ -8,6 +8,7 @@ import ca.uhn.fhir.batch2.jobs.chunk.TypedPidJson;
import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeStep;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexJobParameters;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexStep;
import ca.uhn.fhir.batch2.model.WorkChunk;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
@ -853,9 +854,12 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
IJobDataSink<VoidModel> sink = mock(IJobDataSink.class);
WorkChunk workChunk = mock(WorkChunk.class);
when(workChunk.getId()).thenReturn("chunk-id");
// Test
myCaptureQueriesListener.clear();
RunOutcome outcome = myDeleteExpungeStep.doDeleteExpunge(new ResourceIdListWorkChunkJson(pids, null), sink, "instance-id", "chunk-id", false, null);
RunOutcome outcome = myDeleteExpungeStep.doDeleteExpunge(new ResourceIdListWorkChunkJson(pids, null), sink, "instance-id", workChunk, false, null);
// Verify
assertEquals(1, myCaptureQueriesListener.countSelectQueriesForCurrentThread());

View File

@ -0,0 +1,62 @@
package ca.uhn.fhir.jpa.delete;
import ca.uhn.fhir.batch2.model.WorkChunk;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.delete.batch2.DeleteExpungeSqlBuilder;
import ca.uhn.fhir.jpa.delete.batch2.DeleteExpungeSvcImpl;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class DeleteExpungeSvcImplTest {
@Mock
private EntityManager myEntityManager;
@Mock
private DeleteExpungeSqlBuilder myDeleteExpungeSqlBuilder;
@Mock
private IFulltextSearchSvc myFulltextSearchSvc;
@InjectMocks
private DeleteExpungeSvcImpl myDeleteExpungeSvc;
@Mock
private Appender<ILoggingEvent> myAppender;
@Captor
ArgumentCaptor<ILoggingEvent> myLoggingEvent;
@Test
public void testChunkIdIncludedInNumRecordsDeletedMessage() {
Logger logger = (Logger) LoggerFactory.getLogger(DeleteExpungeSvcImpl.class);
logger.addAppender(myAppender);
when(myDeleteExpungeSqlBuilder.convertPidsToDeleteExpungeSql(Collections.emptyList(), false, 1)).thenReturn(mock(DeleteExpungeSqlBuilder.DeleteExpungeSqlResult.class));
WorkChunk workChunk = mock(WorkChunk.class);
when(workChunk.getId()).thenReturn("abc-123");
myDeleteExpungeSvc.deleteExpunge(Collections.emptyList(), false, 1, workChunk);
verify(myAppender, atLeastOnce()).doAppend(myLoggingEvent.capture());
List<ILoggingEvent> events = myLoggingEvent.getAllValues();
assertEquals(Level.INFO, events.get(0).getLevel());
assertEquals("Chunk[abc-123] - Delete expunge sql commands affected 0 rows", events.get(0).getFormattedMessage());
}
}

View File

@ -79,25 +79,11 @@
<dependency>
<groupId>org.simplejavamail</groupId>
<artifactId>simple-java-mail</artifactId>
<!-- Excluded in favor of jakarta.activation:jakarta.activation-api -->
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<scope>compile</scope>
<!-- Excluded in favor of jakarta.activation:jakarta.activation-api -->
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

View File

@ -352,7 +352,7 @@ public class MdmStorageInterceptor implements IMdmStorageInterceptor {
@SuppressWarnings("unchecked")
private int deleteExpungeGoldenResource(IResourcePersistentId theGoldenPid) {
IDeleteExpungeSvc deleteExpungeSvc = myIMdmClearHelperSvc.getDeleteExpungeSvc();
return deleteExpungeSvc.deleteExpunge(new ArrayList<>(Collections.singleton(theGoldenPid)), false, null);
return deleteExpungeSvc.deleteExpunge(new ArrayList<>(Collections.singleton(theGoldenPid)), false, null, null);
}
private void forbidIfModifyingExternalEidOnTarget(IBaseResource theNewResource, IBaseResource theOldResource) {

View File

@ -21,9 +21,9 @@ package ca.uhn.fhir.rest.server.mail;
import jakarta.annotation.Nonnull;
import org.simplejavamail.api.email.Email;
import org.simplejavamail.api.mailer.AsyncResponse;
import java.util.List;
import java.util.function.Consumer;
public interface IMailSvc {
void sendMail(@Nonnull List<Email> theEmails);
@ -31,7 +31,5 @@ public interface IMailSvc {
void sendMail(@Nonnull Email theEmail);
void sendMail(
@Nonnull Email theEmail,
@Nonnull Runnable theOnSuccess,
@Nonnull AsyncResponse.ExceptionConsumer theErrorHandler);
@Nonnull Email theEmail, @Nonnull Runnable theOnSuccess, @Nonnull Consumer<Throwable> theErrorHandler);
}

View File

@ -20,12 +20,9 @@
package ca.uhn.fhir.rest.server.mail;
import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.Validate;
import org.simplejavamail.MailException;
import org.simplejavamail.api.email.Email;
import org.simplejavamail.api.email.Recipient;
import org.simplejavamail.api.mailer.AsyncResponse;
import org.simplejavamail.api.mailer.AsyncResponse.ExceptionConsumer;
import org.simplejavamail.api.mailer.Mailer;
import org.simplejavamail.api.mailer.config.TransportStrategy;
import org.simplejavamail.mailer.MailerBuilder;
@ -33,6 +30,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class MailSvc implements IMailSvc {
@ -42,14 +41,14 @@ public class MailSvc implements IMailSvc {
private final Mailer myMailer;
public MailSvc(@Nonnull MailConfig theMailConfig) {
Validate.notNull(theMailConfig);
Objects.requireNonNull(theMailConfig);
myMailConfig = theMailConfig;
myMailer = makeMailer(myMailConfig);
}
@Override
public void sendMail(@Nonnull List<Email> theEmails) {
Validate.notNull(theEmails);
Objects.requireNonNull(theEmails);
theEmails.forEach(theEmail -> send(theEmail, new OnSuccess(theEmail), new ErrorHandler(theEmail)));
}
@ -60,21 +59,23 @@ public class MailSvc implements IMailSvc {
@Override
public void sendMail(
@Nonnull Email theEmail, @Nonnull Runnable theOnSuccess, @Nonnull ExceptionConsumer theErrorHandler) {
@Nonnull Email theEmail, @Nonnull Runnable theOnSuccess, @Nonnull Consumer<Throwable> theErrorHandler) {
send(theEmail, theOnSuccess, theErrorHandler);
}
private void send(
@Nonnull Email theEmail, @Nonnull Runnable theOnSuccess, @Nonnull ExceptionConsumer theErrorHandler) {
Validate.notNull(theEmail);
Validate.notNull(theOnSuccess);
Validate.notNull(theErrorHandler);
@Nonnull Email theEmail, @Nonnull Runnable theOnSuccess, @Nonnull Consumer<Throwable> theErrorHandler) {
Objects.requireNonNull(theEmail);
Objects.requireNonNull(theOnSuccess);
Objects.requireNonNull(theErrorHandler);
try {
final AsyncResponse asyncResponse = myMailer.sendMail(theEmail, true);
if (asyncResponse != null) {
asyncResponse.onSuccess(theOnSuccess);
asyncResponse.onException(theErrorHandler);
}
myMailer.sendMail(theEmail, true).whenComplete((result, ex) -> {
if (ex != null) {
theErrorHandler.accept(ex);
} else {
theOnSuccess.run();
}
});
} catch (MailException e) {
theErrorHandler.accept(e);
}
@ -117,7 +118,7 @@ public class MailSvc implements IMailSvc {
}
}
private class ErrorHandler implements ExceptionConsumer {
private class ErrorHandler implements Consumer<Throwable> {
private final Email myEmail;
private ErrorHandler(@Nonnull Email theEmail) {
@ -125,7 +126,7 @@ public class MailSvc implements IMailSvc {
}
@Override
public void accept(Exception t) {
public void accept(Throwable t) {
ourLog.error("Email not sent" + makeMessage(myEmail), t);
}
}

View File

@ -4,6 +4,7 @@ import com.icegreen.greenmail.junit5.GreenMailExtension;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.icegreen.greenmail.util.ServerSetupTest;
import jakarta.annotation.Nonnull;
import jakarta.mail.internet.MimeMessage;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@ -11,7 +12,6 @@ import org.simplejavamail.MailException;
import org.simplejavamail.api.email.Email;
import org.simplejavamail.email.EmailBuilder;
import javax.mail.internet.MimeMessage;
import java.util.Arrays;
import java.util.List;
@ -86,13 +86,14 @@ public class MailSvcIT {
@Test
public void testSendMailWithInvalidToAddressExpectErrorHandler() {
// setup
final Email email = withEmail("xyz");
String invalidEmailAdress = "xyz";
final Email email = withEmail(invalidEmailAdress);
// execute
fixture.sendMail(email,
() -> fail("Should not execute on Success"),
(e) -> {
assertTrue(e instanceof MailException);
assertEquals("Invalid TO address: " + email, e.getMessage());
assertEquals("Invalid TO address: " + invalidEmailAdress, e.getMessage());
});
// validate
assertTrue(ourGreenMail.waitForIncomingEmail(1000, 0));

View File

@ -19,8 +19,14 @@
*/
package ca.uhn.fhir.batch2.jobs.expunge;
import ca.uhn.fhir.batch2.api.*;
import ca.uhn.fhir.batch2.api.IJobDataSink;
import ca.uhn.fhir.batch2.api.IJobStepWorker;
import ca.uhn.fhir.batch2.api.JobExecutionFailedException;
import ca.uhn.fhir.batch2.api.RunOutcome;
import ca.uhn.fhir.batch2.api.StepExecutionDetails;
import ca.uhn.fhir.batch2.api.VoidModel;
import ca.uhn.fhir.batch2.jobs.chunk.ResourceIdListWorkChunkJson;
import ca.uhn.fhir.batch2.model.WorkChunk;
import ca.uhn.fhir.jpa.api.svc.IDeleteExpungeSvc;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
@ -70,7 +76,7 @@ public class DeleteExpungeStep
data,
theDataSink,
theStepExecutionDetails.getInstance().getInstanceId(),
theStepExecutionDetails.getChunkId(),
theStepExecutionDetails.getWorkChunk(),
cascade,
cascadeMaxRounds);
}
@ -80,7 +86,7 @@ public class DeleteExpungeStep
ResourceIdListWorkChunkJson theData,
IJobDataSink<VoidModel> theDataSink,
String theInstanceId,
String theChunkId,
WorkChunk theWorkChunk,
boolean theCascade,
Integer theCascadeMaxRounds) {
RequestDetails requestDetails = new SystemRequestDetails();
@ -91,7 +97,7 @@ public class DeleteExpungeStep
transactionDetails,
theDataSink,
theInstanceId,
theChunkId,
theWorkChunk,
theCascade,
theCascadeMaxRounds);
myHapiTransactionService
@ -108,7 +114,7 @@ public class DeleteExpungeStep
private final RequestDetails myRequestDetails;
private final TransactionDetails myTransactionDetails;
private final IJobDataSink<VoidModel> myDataSink;
private final String myChunkId;
private final WorkChunk myWorkChunk;
private final String myInstanceId;
private final boolean myCascade;
private final Integer myCascadeMaxRounds;
@ -120,7 +126,7 @@ public class DeleteExpungeStep
TransactionDetails theTransactionDetails,
IJobDataSink<VoidModel> theDataSink,
String theInstanceId,
String theChunkId,
WorkChunk theWorkChunk,
boolean theCascade,
Integer theCascadeMaxRounds) {
myData = theData;
@ -128,7 +134,7 @@ public class DeleteExpungeStep
myTransactionDetails = theTransactionDetails;
myDataSink = theDataSink;
myInstanceId = theInstanceId;
myChunkId = theChunkId;
myWorkChunk = theWorkChunk;
myCascade = theCascade;
myCascadeMaxRounds = theCascadeMaxRounds;
}
@ -141,12 +147,13 @@ public class DeleteExpungeStep
public Void doInTransaction(@Nonnull TransactionStatus theStatus) {
List<JpaPid> persistentIds = myData.getResourcePersistentIds(myIdHelperService);
String workChunkId = myWorkChunk.getId();
if (persistentIds.isEmpty()) {
ourLog.info(
"Starting delete expunge work chunk. There are no resources to delete expunge - Instance[{}] Chunk[{}]",
myInstanceId,
myChunkId);
workChunkId);
return null;
}
@ -154,9 +161,15 @@ public class DeleteExpungeStep
"Starting delete expunge work chunk with {} resources - Instance[{}] Chunk[{}]",
persistentIds.size(),
myInstanceId,
myChunkId);
workChunkId);
myRecordCount = myDeleteExpungeSvc.deleteExpunge(persistentIds, myCascade, myCascadeMaxRounds);
myRecordCount = myDeleteExpungeSvc.deleteExpunge(persistentIds, myCascade, myCascadeMaxRounds, myWorkChunk);
ourLog.info(
"Delete expunge finished deleting {} resources - Instance[{}] Chunk[{}]",
myRecordCount,
myInstanceId,
workChunkId);
return null;
}

View File

@ -26,6 +26,7 @@ import ca.uhn.fhir.batch2.api.RunOutcome;
import ca.uhn.fhir.batch2.api.StepExecutionDetails;
import ca.uhn.fhir.batch2.api.VoidModel;
import ca.uhn.fhir.batch2.jobs.chunk.ResourceIdListWorkChunkJson;
import ca.uhn.fhir.batch2.model.WorkChunk;
import ca.uhn.fhir.jpa.api.svc.IDeleteExpungeSvc;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.api.svc.IMdmClearHelperSvc;
@ -96,7 +97,7 @@ public class MdmClearStep implements IJobStepWorker<MdmClearJobParameters, Resou
private final RequestDetails myRequestDetails;
private final TransactionDetails myTransactionDetails;
private final ResourceIdListWorkChunkJson myData;
private final String myChunkId;
private final WorkChunk myWorkChunk;
private final String myInstanceId;
public MdmClearJob(
@ -107,7 +108,7 @@ public class MdmClearStep implements IJobStepWorker<MdmClearJobParameters, Resou
myTransactionDetails = theTransactionDetails;
myData = theStepExecutionDetails.getData();
myInstanceId = theStepExecutionDetails.getInstance().getInstanceId();
myChunkId = theStepExecutionDetails.getChunkId();
myWorkChunk = theStepExecutionDetails.getWorkChunk();
}
@SuppressWarnings("unchecked")
@ -137,7 +138,7 @@ public class MdmClearStep implements IJobStepWorker<MdmClearJobParameters, Resou
"Starting mdm clear work chunk with {} resources - Instance[{}] Chunk[{}]",
thePersistentIds.size(),
myInstanceId,
myChunkId);
myWorkChunk);
StopWatch sw = new StopWatch();
myMdmLinkSvc.deleteLinksWithAnyReferenceToPids(thePersistentIds);
@ -145,7 +146,7 @@ public class MdmClearStep implements IJobStepWorker<MdmClearJobParameters, Resou
// use the expunge service to delete multiple resources at once efficiently
IDeleteExpungeSvc deleteExpungeSvc = myIMdmClearHelperSvc.getDeleteExpungeSvc();
int deletedRecords = deleteExpungeSvc.deleteExpunge(thePersistentIds, false, null);
int deletedRecords = deleteExpungeSvc.deleteExpunge(thePersistentIds, false, null, myWorkChunk);
ourLog.trace(
"Deleted {} of {} golden resources in {}",
@ -160,7 +161,7 @@ public class MdmClearStep implements IJobStepWorker<MdmClearJobParameters, Resou
sw,
sw.formatThroughput(thePersistentIds.size(), TimeUnit.SECONDS),
myInstanceId,
myChunkId);
myWorkChunk);
if (ourClearCompletionCallbackForUnitTest != null) {
ourClearCompletionCallbackForUnitTest.run();

View File

@ -19,13 +19,15 @@
*/
package ca.uhn.fhir.jpa.api.svc;
import ca.uhn.fhir.model.api.IModelJson;
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
import java.util.List;
public interface IDeleteExpungeSvc<T extends IResourcePersistentId<?>> {
int deleteExpunge(List<T> thePersistentIds, boolean theCascade, Integer theCascadeMaxRounds);
<PT extends IModelJson> int deleteExpunge(
List<T> thePersistentIds, boolean theCascade, Integer theCascadeMaxRounds, PT theWorkChunk);
boolean isCascadeSupported();
}

34
pom.xml
View File

@ -869,6 +869,7 @@
<developer>
<id>delopst</id>
<name>Primož Delopst</name>
<organization>Better</organization>
</developer>
<developer>
<id>Zach Smith</id>
@ -1160,27 +1161,38 @@
<dependency>
<groupId>org.simplejavamail</groupId>
<artifactId>simple-java-mail</artifactId>
<version>6.6.1</version>
<version>8.11.2</version>
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<groupId>com.github.bbottema</groupId>
<artifactId>jetbrains-runtime-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>2.1.0-rc-1</version>
<exclusions>
<exclusion>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail-junit5</artifactId>
<version>1.6.4</version>
<version>2.1.0-rc-1</version>
<scope>compile</scope>
</dependency>
<!-- mail end -->