diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index 48711901c07..2c10aae25a5 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 1e38f02cfed..b56416253b2 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index cdc9fb9a19a..b4ce4b0e79c 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-batch/pom.xml b/hapi-fhir-batch/pom.xml index 6f04343198b..c1d10dce87d 100644 --- a/hapi-fhir-batch/pom.xml +++ b/hapi-fhir-batch/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index e2c08f160f5..9853fa18ffb 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -3,14 +3,14 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT pom HAPI FHIR BOM ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index 1b58f737eb2..1bc75d5271c 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml index d4693c0105c..7e84961bde6 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index 315763e4d0b..77106e656f2 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir-cli - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml index 1a2233d3eee..5807b01cc01 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../../hapi-deployable-pom diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index 19df1e60cb2..00acfbb2f29 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index 454ddbbafb5..198b7b59ba9 100644 --- a/hapi-fhir-client-okhttp/pom.xml +++ b/hapi-fhir-client-okhttp/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index 1011dfaa38f..d4e66d1efe8 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index 594a512cc14..658014b7ee1 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index feb772022f5..0e2e4f52a3e 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index 70552e518ee..83809ea2bbf 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3770-added-error-handling-for-batch2.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3770-added-error-handling-for-batch2.yaml new file mode 100644 index 00000000000..732dc9db24a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3770-added-error-handling-for-batch2.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 3770 +title: "Batch2 will have a standard error handling that will fail the job if it fails +a chunk processing for more than 3 times. +Further, added better validation to reindex job to disallow bad urls." diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index 522084f9de1..00504fb69d7 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index 915d263033f..4ad08f7c4a6 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index bf098fdf893..b001e7daca7 100644 --- a/hapi-fhir-jpa/pom.xml +++ b/hapi-fhir-jpa/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 1ceaab27190..863369a8f8e 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java index c23661afa10..4f5c4073385 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.api.JobOperationResultJson; import ca.uhn.fhir.batch2.coordinator.BatchWorkChunk; import ca.uhn.fhir.batch2.model.JobInstance; +import ca.uhn.fhir.batch2.model.MarkWorkChunkAsErrorRequest; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.jpa.dao.data.IBatch2JobInstanceRepository; @@ -198,6 +199,14 @@ public class JpaJobPersistenceImpl implements IJobPersistence { myWorkChunkRepository.updateChunkStatusAndIncrementErrorCountForEndError(theChunkId, new Date(), theErrorMessage, StatusEnum.ERRORED); } + @Override + public Optional markWorkChunkAsErroredAndIncrementErrorCount(MarkWorkChunkAsErrorRequest theParameters) { + markWorkChunkAsErroredAndIncrementErrorCount(theParameters.getChunkId(), theParameters.getErrorMsg()); + Optional op = myWorkChunkRepository.findById(theParameters.getChunkId()); + + return op.map(c -> toChunk(c, theParameters.isIncludeData())); + } + @Override public void markWorkChunkAsFailed(String theChunkId, String theErrorMessage) { myWorkChunkRepository.updateChunkStatusAndIncrementErrorCountForEndError(theChunkId, new Date(), theErrorMessage, StatusEnum.FAILED); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java index 1097610f645..f73fdeebfe7 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java @@ -27,6 +27,7 @@ class JpaJobPersistenceImplTest { @InjectMocks JpaJobPersistenceImpl mySvc; + @Test void cancelSuccess() { // setup diff --git a/hapi-fhir-jpaserver-cql/pom.xml b/hapi-fhir-jpaserver-cql/pom.xml index 1e1a3d026eb..b89e9aa7d9e 100644 --- a/hapi-fhir-jpaserver-cql/pom.xml +++ b/hapi-fhir-jpaserver-cql/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index 53b90ef5838..65bf75fd5a4 100644 --- a/hapi-fhir-jpaserver-mdm/pom.xml +++ b/hapi-fhir-jpaserver-mdm/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 3d78e8bed4f..d620d2f0ce6 100644 --- a/hapi-fhir-jpaserver-model/pom.xml +++ b/hapi-fhir-jpaserver-model/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index e4559e77757..453e499ce36 100755 --- a/hapi-fhir-jpaserver-searchparam/pom.xml +++ b/hapi-fhir-jpaserver-searchparam/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index 87706fa1422..3212b84c639 100644 --- a/hapi-fhir-jpaserver-subscription/pom.xml +++ b/hapi-fhir-jpaserver-subscription/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml index eaede692f68..988724210b7 100644 --- a/hapi-fhir-jpaserver-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java index f8f8d79c183..434669adce2 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java @@ -28,6 +28,9 @@ import org.awaitility.core.ConditionTimeoutException; import org.hamcrest.Matchers; import org.springframework.beans.factory.annotation.Autowired; +import java.time.Duration; +import java.util.concurrent.TimeUnit; + import java.util.Collection; import java.util.List; @@ -71,6 +74,17 @@ public class Batch2JobHelper { }, equalTo(StatusEnum.CANCELLED)); } + public JobInstance awaitJobHitsStatusInTime(String theId, int theSeconds, StatusEnum... theStatuses) { + await().atMost(theSeconds, TimeUnit.SECONDS) + .pollDelay(Duration.ofSeconds(10)) + .until(() -> { + myJobMaintenanceService.runMaintenancePass(); + return myJobCoordinator.getInstance(theId).getStatus(); + }, Matchers.in(theStatuses)); + + return myJobCoordinator.getInstance(theId); + } + public void awaitJobInProgress(String theId) { await().until(() -> { myJobMaintenanceService.runMaintenancePass(); diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java index 1067ff4f941..06de5234d2e 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.batch2.api.IJobDataSink; import ca.uhn.fhir.batch2.api.IJobMaintenanceService; import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.api.IJobStepWorker; +import ca.uhn.fhir.batch2.api.ILastJobStepWorker; import ca.uhn.fhir.batch2.api.IReductionStepWorker; import ca.uhn.fhir.batch2.api.JobExecutionFailedException; import ca.uhn.fhir.batch2.api.RunOutcome; @@ -17,6 +18,11 @@ import ca.uhn.fhir.batch2.model.ChunkOutcome; import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobInstanceStartRequest; +import ca.uhn.fhir.batch2.model.JobWorkNotificationJsonMessage; +import ca.uhn.fhir.batch2.model.StatusEnum; +import ca.uhn.fhir.jpa.subscription.channel.api.ChannelConsumerSettings; +import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory; +import ca.uhn.fhir.jpa.subscription.channel.impl.LinkedBlockingChannel; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.jpa.test.Batch2JobHelper; import ca.uhn.fhir.model.api.IModelJson; @@ -24,11 +30,16 @@ import ca.uhn.fhir.util.JsonUtil; import ca.uhn.test.concurrency.LatchTimedOutError; import ca.uhn.test.concurrency.PointcutLatch; import com.fasterxml.jackson.annotation.JsonProperty; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHandler; +import org.springframework.messaging.support.ExecutorChannelInterceptor; import javax.annotation.Nonnull; import java.util.ArrayList; @@ -39,6 +50,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; +import static ca.uhn.fhir.batch2.config.BaseBatch2Config.CHANNEL_NAME; +import static ca.uhn.fhir.batch2.coordinator.StepExecutionSvc.MAX_CHUNK_ERROR_COUNT; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -58,6 +71,8 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { IJobMaintenanceService myJobMaintenanceService; @Autowired Batch2JobHelper myBatch2JobHelper; + @Autowired + private IChannelFactory myChannelFactory; @Autowired IJobPersistence myJobPersistence; @@ -65,6 +80,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { private final PointcutLatch myFirstStepLatch = new PointcutLatch("First Step"); private final PointcutLatch myLastStepLatch = new PointcutLatch("Last Step"); private IJobCompletionHandler myCompletionHandler; + private LinkedBlockingChannel myWorkChannel; private static RunOutcome callLatch(PointcutLatch theLatch, StepExecutionDetails theStep) { theLatch.call(theStep); @@ -73,7 +89,13 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { @BeforeEach public void before() { - myCompletionHandler = details -> {}; + myCompletionHandler = details -> {}; + myWorkChannel = (LinkedBlockingChannel) myChannelFactory.getOrCreateReceiver(CHANNEL_NAME, JobWorkNotificationJsonMessage.class, new ChannelConsumerSettings()); + } + + @AfterEach + public void after() { + myWorkChannel.clearInterceptorsForUnitTest(); } @Test @@ -123,7 +145,6 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { myLastStepLatch.awaitExpected(); } - @Test public void testFastTrack_Maintenance_do_not_both_call_CompletionHandler() throws InterruptedException { IJobStepWorker firstStep = (step, sink) -> { @@ -189,7 +210,6 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { myLastStepLatch.awaitExpected(); } - @Test public void testJobDefinitionWithReductionStepIT() throws InterruptedException { // setup @@ -371,6 +391,69 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { myBatch2JobHelper.awaitJobCancelled(instanceId); } + @Test + public void testStepRunFailure_continuouslyThrows_marksJobFailed() { + AtomicInteger interceptorCounter = new AtomicInteger(); + myWorkChannel.addInterceptor(new ExecutorChannelInterceptor() { + @Override + public void afterMessageHandled(Message message, MessageChannel channel, MessageHandler handler, Exception ex) { + if (ex != null) { + interceptorCounter.incrementAndGet(); + ourLog.info("Work Channel Exception thrown: {}. Resending message", ex.getMessage()); + channel.send(message); + } + } + }); + + // setup + AtomicInteger counter = new AtomicInteger(); + // step 1 + IJobStepWorker first = (step, sink) -> { + counter.getAndIncrement(); + throw new RuntimeException("Exception"); + }; + // final step + ILastJobStepWorker last = (step, sink) -> { + fail("We should never hit this last step"); + return RunOutcome.SUCCESS; + }; + // job definition + String jobId = new Exception().getStackTrace()[0].getMethodName(); + JobDefinition jd = JobDefinition.newBuilder() + .setJobDefinitionId(jobId) + .setJobDescription("test job") + .setJobDefinitionVersion(TEST_JOB_VERSION) + .setParametersType(TestJobParameters.class) + .gatedExecution() + .addFirstStep( + FIRST_STEP_ID, + "Test first step", + FirstStepOutput.class, + first + ) + .addLastStep( + LAST_STEP_ID, + "Test last step", + last + ) + .build(); + myJobDefinitionRegistry.addJobDefinition(jd); + // test + JobInstanceStartRequest request = buildRequest(jobId); + myFirstStepLatch.setExpectedCount(1); + String instanceId = myJobCoordinator.startInstance(request); + JobInstance instance = myBatch2JobHelper.awaitJobHitsStatusInTime(instanceId, + 12, // we want to wait a long time (2 min here) cause backoff is incremental + StatusEnum.FAILED, StatusEnum.ERRORED // error states + ); + + assertEquals(MAX_CHUNK_ERROR_COUNT + 1, counter.get()); + assertEquals(MAX_CHUNK_ERROR_COUNT, interceptorCounter.get()); + + assertTrue(instance.getStatus() == StatusEnum.FAILED + || instance.getStatus() == StatusEnum.ERRORED); + } + @Nonnull private JobInstanceStartRequest buildRequest(String jobId) { JobInstanceStartRequest request = new JobInstanceStartRequest(); diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/bulk/imprt2/BulkImportR4Test.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/bulk/imprt2/BulkImportR4Test.java index 6276b7850ac..195332023c2 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/bulk/imprt2/BulkImportR4Test.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/bulk/imprt2/BulkImportR4Test.java @@ -185,7 +185,7 @@ public class BulkImportR4Test extends BaseJpaR4Test { assertNotNull(instance.getCreateTime()); assertNotNull(instance.getStartTime()); assertNull(instance.getEndTime()); - assertThat(instance.getErrorMessage(), containsString("NullPointerException: This is an exception")); + assertThat(instance.getErrorMessage(), containsString("This is an exception")); }); } finally { diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java index 33e5b128174..6c3779f837c 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java @@ -129,7 +129,7 @@ public class ReindexJobTest extends BaseJpaR4Test { // Verify assertEquals(StatusEnum.ERRORED, outcome.getStatus()); - assertEquals("java.lang.NullPointerException: foo message", outcome.getErrorMessage()); + assertEquals("foo message", outcome.getErrorMessage()); } @Test diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index 8fc4f4fddef..2ca8a8186ce 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 8af75a2b980..758a1bf6527 100644 --- a/hapi-fhir-server-mdm/pom.xml +++ b/hapi-fhir-server-mdm/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index a5b836d628f..f9e0de9e422 100644 --- a/hapi-fhir-server-openapi/pom.xml +++ b/hapi-fhir-server-openapi/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index 73e8d67a48f..dcc135356da 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml index 708a4cdc153..7c59060a165 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml index 49f6646d6aa..f2811a6c718 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT hapi-fhir-spring-boot-sample-client-apache diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml index a3cfe0ac80f..bb03521f05f 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT hapi-fhir-spring-boot-sample-client-okhttp diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index f898db94f74..c4c9340e3af 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT hapi-fhir-spring-boot-sample-server-jersey diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index 25d8f341423..a6e1fa8d89f 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT hapi-fhir-spring-boot-samples diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index 3bbf1f44270..9d9767e8047 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index e6dea8e8605..c8cd5a98676 100644 --- a/hapi-fhir-spring-boot/pom.xml +++ b/hapi-fhir-spring-boot/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index e04ea6a1aae..3597a607fb7 100644 --- a/hapi-fhir-sql-migrate/pom.xml +++ b/hapi-fhir-sql-migrate/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-jobs/pom.xml b/hapi-fhir-storage-batch2-jobs/pom.xml index 99469bb5135..f0213c484cf 100644 --- a/hapi-fhir-storage-batch2-jobs/pom.xml +++ b/hapi-fhir-storage-batch2-jobs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexJobParametersValidator.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexJobParametersValidator.java index 3b475160327..49185755eed 100644 --- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexJobParametersValidator.java +++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexJobParametersValidator.java @@ -21,13 +21,19 @@ package ca.uhn.fhir.batch2.jobs.reindex; */ import ca.uhn.fhir.batch2.api.IJobParametersValidator; +import ca.uhn.fhir.batch2.jobs.parameters.PartitionedUrl; import ca.uhn.fhir.batch2.jobs.parameters.UrlListValidator; +import ca.uhn.fhir.util.UrlUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ReindexJobParametersValidator implements IJobParametersValidator { + private final UrlListValidator myUrlListValidator; public ReindexJobParametersValidator(UrlListValidator theUrlListValidator) { @@ -37,6 +43,21 @@ public class ReindexJobParametersValidator implements IJobParametersValidator validate(@NotNull ReindexJobParameters theParameters) { - return myUrlListValidator.validatePartitionedUrls(theParameters.getPartitionedUrls()); + List errors = myUrlListValidator.validatePartitionedUrls(theParameters.getPartitionedUrls()); + + if (errors == null || errors.isEmpty()) { + // only check if there's no other errors (new list to fix immutable issues) + errors = new ArrayList<>(); + List urls = theParameters.getPartitionedUrls(); + for (PartitionedUrl purl : urls) { + String url = purl.getUrl(); + + if (url.contains(" ") || url.contains("\n") || url.contains("\t")) { + errors.add("Invalid URL. URL cannot contain spaces : " + url); + } + } + } + + return errors; } } diff --git a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexJobParametersValidatorTest.java b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexJobParametersValidatorTest.java new file mode 100644 index 00000000000..f8ee5873a2c --- /dev/null +++ b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexJobParametersValidatorTest.java @@ -0,0 +1,47 @@ +package ca.uhn.fhir.batch2.jobs.reindex; + +import ca.uhn.fhir.batch2.jobs.parameters.UrlListValidator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Value; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(MockitoExtension.class) +public class ReindexJobParametersValidatorTest { + + @Mock + private UrlListValidator myListValidator; + + @InjectMocks + private ReindexJobParametersValidator myValidator; + + @ParameterizedTest + @ValueSource(strings = { "\n", " ", "\t" }) + public void validate_urlWithSpace_fails(String theWhiteSpaceChar) { + List errors = runTestWithUrl("Patient," + theWhiteSpaceChar + "Practitioner"); + + // verify + assertFalse(errors.isEmpty()); + assertTrue(errors.get(0).contains("Invalid URL. URL cannot contain spaces")); + } + + private List runTestWithUrl(String theUrl) { + // setup + ReindexJobParameters parameters = new ReindexJobParameters(); + parameters.addUrl(theUrl); + + // test + List errors = myValidator.validate(parameters); + + return errors; + } +} diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 662883fc325..1c76d1090a6 100644 --- a/hapi-fhir-storage-batch2/pom.xml +++ b/hapi-fhir-storage-batch2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java index d368ab54bb0..52d532b874e 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.batch2.api; import ca.uhn.fhir.batch2.coordinator.BatchWorkChunk; import ca.uhn.fhir.batch2.model.JobInstance; +import ca.uhn.fhir.batch2.model.MarkWorkChunkAsErrorRequest; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; @@ -100,8 +101,26 @@ public interface IJobPersistence { * * @param theChunkId The chunk ID */ + @Deprecated void markWorkChunkAsErroredAndIncrementErrorCount(String theChunkId, String theErrorMessage); + /** + * Marks a given chunk as having errored (ie, may be recoverable) + * + * Returns the work chunk. + * + * NB: For backwards compatibility reasons, it could be an empty optional, but + * this doesn't mean it has no workchunk (just implementers are not updated) + * + * @param theParameters - the parameters for marking the workchunk with error + * @return - workchunk optional, if available. + */ + default Optional markWorkChunkAsErroredAndIncrementErrorCount(MarkWorkChunkAsErrorRequest theParameters) { + // old method - please override me + markWorkChunkAsErroredAndIncrementErrorCount(theParameters.getChunkId(), theParameters.getErrorMsg()); + return Optional.empty(); // returning empty so as not to break implementers + } + /** * Marks a given chunk as having failed (i.e. probably not recoverable) * diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvc.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvc.java index c2a9353abf4..873c3cdbd05 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvc.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvc.java @@ -36,6 +36,7 @@ import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.JobDefinitionStep; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobWorkCursor; +import ca.uhn.fhir.batch2.model.MarkWorkChunkAsErrorRequest; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.i18n.Msg; @@ -48,10 +49,23 @@ import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Optional; public class StepExecutionSvc { private static final Logger ourLog = LoggerFactory.getLogger(StepExecutionSvc.class); + // TODO + /** + * This retry only works if your channel producer supports + * retries on message processing exceptions. + * + * What's more, we may one day want to have this configurable + * by the caller. + * But since this is not a feature of HAPI, + * this has not been done yet. + */ + public static final int MAX_CHUNK_ERROR_COUNT = 3; + private final IJobPersistence myJobPersistence; private final BatchJobSender myBatchJobSender; @@ -303,7 +317,20 @@ public class StepExecutionSvc { } catch (Exception e) { ourLog.error("Failure executing job {} step {}", jobDefinitionId, targetStepId, e); if (theStepExecutionDetails.hasAssociatedWorkChunk()) { - myJobPersistence.markWorkChunkAsErroredAndIncrementErrorCount(chunkId, e.toString()); + MarkWorkChunkAsErrorRequest parameters = new MarkWorkChunkAsErrorRequest(); + parameters.setChunkId(chunkId); + parameters.setErrorMsg(e.getMessage()); + Optional updatedOp = myJobPersistence.markWorkChunkAsErroredAndIncrementErrorCount(parameters); + if (updatedOp.isPresent()) { + WorkChunk chunk = updatedOp.get(); + + // TODO - marking for posterity + // see comments on MAX_CHUNK_ERROR_COUNT + if (chunk.getErrorCount() > MAX_CHUNK_ERROR_COUNT) { + myJobPersistence.markWorkChunkAsFailed(chunkId, "Too many errors: " + chunk.getErrorCount()); + return false; + } + } } throw new JobStepFailedException(Msg.code(2041) + e.getMessage(), e); } catch (Throwable t) { diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java index ff3ff56e0b5..3242f803b9e 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java @@ -23,6 +23,7 @@ package ca.uhn.fhir.batch2.coordinator; import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.api.JobOperationResultJson; import ca.uhn.fhir.batch2.model.JobInstance; +import ca.uhn.fhir.batch2.model.MarkWorkChunkAsErrorRequest; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; @@ -92,6 +93,11 @@ public class SynchronizedJobPersistenceWrapper implements IJobPersistence { myWrap.markWorkChunkAsErroredAndIncrementErrorCount(theChunkId, theErrorMessage); } + @Override + public Optional markWorkChunkAsErroredAndIncrementErrorCount(MarkWorkChunkAsErrorRequest theParameters) { + return myWrap.markWorkChunkAsErroredAndIncrementErrorCount(theParameters); + } + @Override public synchronized void markWorkChunkAsFailed(String theChunkId, String theErrorMessage) { myWrap.markWorkChunkAsFailed(theChunkId, theErrorMessage); diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/MarkWorkChunkAsErrorRequest.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/MarkWorkChunkAsErrorRequest.java new file mode 100644 index 00000000000..1cb3cbce20a --- /dev/null +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/MarkWorkChunkAsErrorRequest.java @@ -0,0 +1,33 @@ +package ca.uhn.fhir.batch2.model; + +public class MarkWorkChunkAsErrorRequest { + private String myChunkId; + + private String myErrorMsg; + + private boolean myIncludeData; + + public String getChunkId() { + return myChunkId; + } + + public void setChunkId(String theChunkId) { + myChunkId = theChunkId; + } + + public String getErrorMsg() { + return myErrorMsg; + } + + public void setErrorMsg(String theErrorMsg) { + myErrorMsg = theErrorMsg; + } + + public boolean isIncludeData() { + return myIncludeData; + } + + public void setIncludeData(boolean theIncludeData) { + myIncludeData = theIncludeData; + } +} diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java index 1657eff4aad..83775bd4dc0 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java @@ -116,6 +116,7 @@ public enum StatusEnum { retVal = ourNotEndedStatuses; return retVal; } + @Nonnull private static void initializeStaticEndedStatuses() { EnumSet endedSet = EnumSet.noneOf(StatusEnum.class); diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java index 245a0ac307f..6314b615461 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java @@ -12,6 +12,7 @@ import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobInstanceStartRequest; import ca.uhn.fhir.batch2.model.JobWorkNotification; import ca.uhn.fhir.batch2.model.JobWorkNotificationJsonMessage; +import ca.uhn.fhir.batch2.model.MarkWorkChunkAsErrorRequest; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.jpa.subscription.channel.api.IChannelReceiver; @@ -245,8 +246,11 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { assertEquals(PARAM_2_VALUE, params.getParam2()); assertEquals(PASSWORD_VALUE, params.getPassword()); - verify(myJobInstancePersister, times(1)).markWorkChunkAsErroredAndIncrementErrorCount(eq(CHUNK_ID), myErrorMessageCaptor.capture()); - assertEquals("java.lang.NullPointerException: This is an error message", myErrorMessageCaptor.getValue()); + ArgumentCaptor parametersArgumentCaptor = ArgumentCaptor.forClass(MarkWorkChunkAsErrorRequest.class); + verify(myJobInstancePersister, times(1)).markWorkChunkAsErroredAndIncrementErrorCount(parametersArgumentCaptor.capture()); + MarkWorkChunkAsErrorRequest capturedParams = parametersArgumentCaptor.getValue(); + assertEquals(CHUNK_ID, capturedParams.getChunkId()); + assertEquals("This is an error message", capturedParams.getErrorMsg()); } @Test diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvcTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvcTest.java index 0326ddacf8d..9e2b455f7bd 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvcTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/StepExecutionSvcTest.java @@ -19,6 +19,7 @@ import ca.uhn.fhir.batch2.model.JobDefinitionReductionStep; import ca.uhn.fhir.batch2.model.JobDefinitionStep; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobWorkCursor; +import ca.uhn.fhir.batch2.model.MarkWorkChunkAsErrorRequest; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.model.WorkChunkData; @@ -34,9 +35,12 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; @@ -492,11 +496,70 @@ public class StepExecutionSvcTest { fail("Expected Exception to be thrown"); } catch (JobStepFailedException jobStepFailedException) { assertTrue(jobStepFailedException.getMessage().contains(msg)); - } catch (Exception anythingElse) { - fail(anythingElse.getMessage()); } } + @Test + public void doExecution_stepWorkerThrowsRandomExceptionForever_eventuallyMarksAsFailedAndReturnsFalse() { + // setup + int counter = 0; + AtomicInteger errorCounter = new AtomicInteger(); + String errorMsg = "my Error Message"; + JobInstance jobInstance = getTestJobInstance(); + WorkChunk chunk = new WorkChunk(); + chunk.setId("chunkId"); + chunk.setData(new StepInputData()); + + JobWorkCursor workCursor = mock(JobWorkCursor.class); + + JobDefinitionStep step = mockOutWorkCursor(StepType.INTERMEDIATE, workCursor, true, false); + + // when + when(myNonReductionStep.run(any(), any())) + .thenThrow(new RuntimeException(errorMsg)); + when(myJobPersistence.markWorkChunkAsErroredAndIncrementErrorCount(any(MarkWorkChunkAsErrorRequest.class))) + .thenAnswer((p) -> { + WorkChunk ec = new WorkChunk(); + ec.setId(chunk.getId()); + int count = errorCounter.getAndIncrement(); + ec.setErrorCount(count); + return Optional.of(ec); + }); + + // test + Boolean processedOutcomeSuccessfully = null; + do { + try { + JobStepExecutorOutput output = myExecutorSvc.doExecution( + workCursor, + jobInstance, + chunk + ); + /* + * Getting a value here means we are no longer + * throwing exceptions. Which is the desired outcome. + * We just now need to ensure that this outcome is + * "false" + */ + processedOutcomeSuccessfully = output.isSuccessful(); + } catch (JobStepFailedException ex) { + assertTrue(ex.getMessage().contains(errorMsg)); + counter++; + } + /* + * +2 because... + * we check for > MAX_CHUNK_ERROR_COUNT (+1) + * we want it to run one extra time here (+1) + */ + } while (processedOutcomeSuccessfully == null && counter < StepExecutionSvc.MAX_CHUNK_ERROR_COUNT + 2); + + // verify + assertNotNull(processedOutcomeSuccessfully); + // +1 because of the > MAX_CHUNK_ERROR_COUNT check + assertEquals(StepExecutionSvc.MAX_CHUNK_ERROR_COUNT + 1, counter); + assertFalse(processedOutcomeSuccessfully); + } + private void runExceptionThrowingTest(Exception theExceptionToThrow) { // setup JobInstance jobInstance = getTestJobInstance(); diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index ce925743bf4..ea823379a2b 100644 --- a/hapi-fhir-storage-mdm/pom.xml +++ b/hapi-fhir-storage-mdm/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml index 6d07c1a54cb..b522ba74de9 100644 --- a/hapi-fhir-storage-test-utilities/pom.xml +++ b/hapi-fhir-storage-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index ee50e83ecf4..4c45f819d3b 100644 --- a/hapi-fhir-storage/pom.xml +++ b/hapi-fhir-storage/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/patch/XmlPatchUtils.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/patch/XmlPatchUtils.java index 4477b0ed2d4..f836b314c49 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/patch/XmlPatchUtils.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/patch/XmlPatchUtils.java @@ -1,7 +1,7 @@ package ca.uhn.fhir.jpa.patch; -import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import com.github.dnault.xmlpatch.Patcher; diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannel.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannel.java index 71e4560b073..a22401f484a 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannel.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannel.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.jpa.subscription.channel.api.IChannelProducer; import ca.uhn.fhir.jpa.subscription.channel.api.IChannelReceiver; import org.springframework.messaging.support.ExecutorSubscribableChannel; +import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -44,9 +45,7 @@ public class LinkedBlockingChannel extends ExecutorSubscribableChannel implement } public void clearInterceptorsForUnitTest() { - while (getInterceptors().size() > 0) { - removeInterceptor(0); - } + setInterceptors(new ArrayList<>()); } @Override diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannelFactory.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannelFactory.java index 6742c9b4a2f..fc363c273f7 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannelFactory.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/subscription/channel/impl/LinkedBlockingChannelFactory.java @@ -34,6 +34,7 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; import javax.annotation.PreDestroy; import java.util.Collections; import java.util.HashMap; @@ -76,41 +77,44 @@ public class LinkedBlockingChannelFactory implements IChannelFactory { // TODO - does this need retry settings? final String channelName = myChannelNamer.getChannelName(theChannelName, theChannelSettings); - return myChannels.computeIfAbsent(channelName, t -> { + return myChannels.computeIfAbsent(channelName, t -> buildLinkedBlockingChannel(theConcurrentConsumers, channelName)); + } - String threadNamingPattern = channelName + "-%d"; + @Nonnull + private LinkedBlockingChannel buildLinkedBlockingChannel(int theConcurrentConsumers, String channelName) { + String threadNamingPattern = channelName + "-%d"; - ThreadFactory threadFactory = new BasicThreadFactory.Builder() - .namingPattern(threadNamingPattern) - .uncaughtExceptionHandler(uncaughtExceptionHandler(channelName)) - .daemon(false) - .priority(Thread.NORM_PRIORITY) - .build(); + ThreadFactory threadFactory = new BasicThreadFactory.Builder() + .namingPattern(threadNamingPattern) + .uncaughtExceptionHandler(uncaughtExceptionHandler(channelName)) + .daemon(false) + .priority(Thread.NORM_PRIORITY) + .build(); - LinkedBlockingQueue queue = new LinkedBlockingQueue<>(SubscriptionConstants.DELIVERY_EXECUTOR_QUEUE_SIZE); - RejectedExecutionHandler rejectedExecutionHandler = (theRunnable, theExecutor) -> { - ourLog.info("Note: Executor queue is full ({} elements), waiting for a slot to become available!", queue.size()); - StopWatch sw = new StopWatch(); - try { - queue.put(theRunnable); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RejectedExecutionException(Msg.code(568) + "Task " + theRunnable.toString() + - " rejected from " + e); - } - ourLog.info("Slot become available after {}ms", sw.getMillis()); - }; - ThreadPoolExecutor executor = new ThreadPoolExecutor( - theConcurrentConsumers, - theConcurrentConsumers, - 0L, - TimeUnit.MILLISECONDS, - queue, - threadFactory, - rejectedExecutionHandler); - return new LinkedBlockingChannel(channelName, executor, queue); + LinkedBlockingQueue queue = new LinkedBlockingQueue<>(SubscriptionConstants.DELIVERY_EXECUTOR_QUEUE_SIZE); + RejectedExecutionHandler rejectedExecutionHandler = (theRunnable, theExecutor) -> { + ourLog.info("Note: Executor queue is full ({} elements), waiting for a slot to become available!", queue.size()); + StopWatch sw = new StopWatch(); + try { + queue.put(theRunnable); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RejectedExecutionException(Msg.code(568) + "Task " + theRunnable.toString() + + " rejected from " + e); + } + ourLog.info("Slot become available after {}ms", sw.getMillis()); + }; + ThreadPoolExecutor executor = new ThreadPoolExecutor( + theConcurrentConsumers, + theConcurrentConsumers, + 0L, + TimeUnit.MILLISECONDS, + queue, + threadFactory, + rejectedExecutionHandler); - }); + LinkedBlockingChannel retval = new LinkedBlockingChannel(channelName, executor, queue); + return retval; } private Thread.UncaughtExceptionHandler uncaughtExceptionHandler(String theChannelName) { diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index 8302ec04709..84843bcb545 100644 --- a/hapi-fhir-structures-dstu2.1/pom.xml +++ b/hapi-fhir-structures-dstu2.1/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index b0760e001dd..dcbedfab110 100644 --- a/hapi-fhir-structures-dstu2/pom.xml +++ b/hapi-fhir-structures-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index 94808234717..ca10663a30c 100644 --- a/hapi-fhir-structures-dstu3/pom.xml +++ b/hapi-fhir-structures-dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index 2f77659a569..fd5ef3c4094 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index 62e11e88d93..0ff8aaab966 100644 --- a/hapi-fhir-structures-r4/pom.xml +++ b/hapi-fhir-structures-r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index 3370977fb55..568537ed37a 100644 --- a/hapi-fhir-structures-r5/pom.xml +++ b/hapi-fhir-structures-r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index 70b7b38db91..46e312f19c8 100644 --- a/hapi-fhir-test-utilities/pom.xml +++ b/hapi-fhir-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index 061234832a7..ccf96613ecd 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index 6b2c4412db6..2ec61f888ad 100644 --- a/hapi-fhir-validation-resources-dstu2.1/pom.xml +++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml index f36f507363d..8775b09c527 100644 --- a/hapi-fhir-validation-resources-dstu2/pom.xml +++ b/hapi-fhir-validation-resources-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml index fff7c5f172e..edcab369e62 100644 --- a/hapi-fhir-validation-resources-dstu3/pom.xml +++ b/hapi-fhir-validation-resources-dstu3/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml index 63d2f5faaf6..5e8883fc636 100644 --- a/hapi-fhir-validation-resources-r4/pom.xml +++ b/hapi-fhir-validation-resources-r4/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml index 6318c468787..1c08994a734 100644 --- a/hapi-fhir-validation-resources-r5/pom.xml +++ b/hapi-fhir-validation-resources-r5/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 87a1911de5c..07f41fc1f58 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 394ecd93bc8..588d43672c5 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml @@ -58,37 +58,37 @@ ca.uhn.hapi.fhir hapi-fhir-structures-dstu3 - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-structures-hl7org-dstu2 - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-structures-r4 - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-structures-r5 - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-validation-resources-dstu2 - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-validation-resources-dstu3 - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-validation-resources-r4 - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT org.apache.velocity diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index a9db3a2641f..7fbb73f01d1 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index e89d1077c41..78931b57bb0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. https://hapifhir.io @@ -2015,7 +2015,7 @@ ca.uhn.hapi.fhir hapi-fhir-checkstyle - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index 9338a3e152e..5af408dc72f 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml index fa247f6a790..c1c34084df1 100644 --- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml index 2a5555cd21d..533ddffaedb 100644 --- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.1.0-PRE13-SNAPSHOT + 6.1.0-PRE14-SNAPSHOT ../../pom.xml