From 650f35ce9261a9440707722cc6ad3393d20f6f46 Mon Sep 17 00:00:00 2001 From: Martha Date: Fri, 28 Jun 2024 15:25:07 -0700 Subject: [PATCH] Separate basic partition provider logic so it can be reused by Mongo. Update documentation. --- .../server_jpa_partitioning/partitioning.md | 6 +-- .../uhn/fhir/jpa/batch2/JpaBatch2Config.java | 2 +- ...rovider.java => JpaPartitionProvider.java} | 9 ++-- ....java => JpaJobPartitionProviderTest.java} | 4 +- .../fhir/batch2/config/BaseBatch2Config.java | 8 ++++ .../coordinator/JobPartitionProvider.java | 23 ++++++++++ .../coordinator/JobPartitionProviderTest.java | 43 +++++++++++++++++++ 7 files changed, 84 insertions(+), 11 deletions(-) rename hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/{JobPartitionProvider.java => JpaPartitionProvider.java} (85%) rename hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/{JobPartitionProviderTest.java => JpaJobPartitionProviderTest.java} (96%) create mode 100644 hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProvider.java create mode 100644 hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProviderTest.java diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_partitioning/partitioning.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_partitioning/partitioning.md index 12b23e69208..c8052de8109 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_partitioning/partitioning.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_partitioning/partitioning.md @@ -130,14 +130,14 @@ Once enabled, HTTP Requests to the FHIR server must include the name of the part POST www.example.com/fhir/Patient ``` -With partitioning enabled, if we were to now create a patient in the `DEFAULT` paritition, the request would now look like this: +With partitioning enabled, if we were to now create a patient in the `P1` partition, the request would now look like this: ``` -POST www.example.com/fhir/DEFAULT/Patient +POST www.example.com/fhir/P1/Patient ``` -Failure to add a partition name to the request path will result in an error when multitenancy is enabled. +If a tenant name is not provided in the request path, the request will default the tenant and use will use the 'DEFAULT' partition. # Limitations diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java index bdc9c2d45bf..3cab50228e1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java @@ -59,6 +59,6 @@ public class JpaBatch2Config extends BaseBatch2Config { @Bean public IJobPartitionProvider jobPartitionProvider( IRequestPartitionHelperSvc theRequestPartitionHelperSvc, IPartitionLookupSvc thePartitionLookupSvc) { - return new JobPartitionProvider(theRequestPartitionHelperSvc, thePartitionLookupSvc); + return new JpaPartitionProvider(theRequestPartitionHelperSvc, thePartitionLookupSvc); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JobPartitionProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaPartitionProvider.java similarity index 85% rename from hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JobPartitionProvider.java rename to hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaPartitionProvider.java index a133bde7a1a..d52806cf46b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JobPartitionProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaPartitionProvider.java @@ -1,6 +1,6 @@ package ca.uhn.fhir.jpa.batch2; -import ca.uhn.fhir.batch2.api.IJobPartitionProvider; +import ca.uhn.fhir.batch2.coordinator.JobPartitionProvider; import ca.uhn.fhir.interceptor.model.RequestPartitionId; import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc; @@ -14,13 +14,12 @@ import java.util.stream.Collectors; * The default implementation, which uses {@link IRequestPartitionHelperSvc} and {@link IPartitionLookupSvc} to compute the partition to run a batch2 job. * The ladder will be used to handle cases when the job is configured to run against all partitions (bulk system operation). */ -public class JobPartitionProvider implements IJobPartitionProvider { - private final IRequestPartitionHelperSvc myRequestPartitionHelperSvc; +public class JpaPartitionProvider extends JobPartitionProvider { private final IPartitionLookupSvc myPartitionLookupSvc; - public JobPartitionProvider( + public JpaPartitionProvider( IRequestPartitionHelperSvc theRequestPartitionHelperSvc, IPartitionLookupSvc thePartitionLookupSvc) { - myRequestPartitionHelperSvc = theRequestPartitionHelperSvc; + super(theRequestPartitionHelperSvc); myPartitionLookupSvc = thePartitionLookupSvc; } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JobPartitionProviderTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPartitionProviderTest.java similarity index 96% rename from hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JobPartitionProviderTest.java rename to hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPartitionProviderTest.java index aab9c65a3c4..a480d09dcc2 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JobPartitionProviderTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPartitionProviderTest.java @@ -21,13 +21,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class JobPartitionProviderTest { +public class JpaJobPartitionProviderTest { @Mock private IRequestPartitionHelperSvc myRequestPartitionHelperSvc; @Mock private IPartitionLookupSvc myPartitionLookupSvc; @InjectMocks - private JobPartitionProvider myJobPartitionProvider; + private JpaPartitionProvider myJobPartitionProvider; @Test public void getPartitions_requestSpecificPartition_returnsPartition() { diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/config/BaseBatch2Config.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/config/BaseBatch2Config.java index d2bff951f83..d403ee0f287 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/config/BaseBatch2Config.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/config/BaseBatch2Config.java @@ -21,11 +21,13 @@ package ca.uhn.fhir.batch2.config; import ca.uhn.fhir.batch2.api.IJobCoordinator; import ca.uhn.fhir.batch2.api.IJobMaintenanceService; +import ca.uhn.fhir.batch2.api.IJobPartitionProvider; import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.api.IReductionStepExecutorService; import ca.uhn.fhir.batch2.channel.BatchJobSender; import ca.uhn.fhir.batch2.coordinator.JobCoordinatorImpl; import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry; +import ca.uhn.fhir.batch2.coordinator.JobPartitionProvider; import ca.uhn.fhir.batch2.coordinator.ReductionStepExecutorServiceImpl; import ca.uhn.fhir.batch2.coordinator.WorkChunkProcessor; import ca.uhn.fhir.batch2.maintenance.JobMaintenanceServiceImpl; @@ -33,6 +35,7 @@ import ca.uhn.fhir.batch2.model.JobWorkNotificationJsonMessage; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import ca.uhn.fhir.jpa.model.sched.ISchedulerService; +import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; import ca.uhn.fhir.jpa.subscription.channel.api.ChannelConsumerSettings; import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings; import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory; @@ -139,4 +142,9 @@ public abstract class BaseBatch2Config { protected int getConcurrentConsumers() { return 4; } + + @Bean + public IJobPartitionProvider jobPartitionProvider(IRequestPartitionHelperSvc theRequestPartitionHelperSvc) { + return new JobPartitionProvider(theRequestPartitionHelperSvc); + } } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProvider.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProvider.java new file mode 100644 index 00000000000..c129ce0c38e --- /dev/null +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProvider.java @@ -0,0 +1,23 @@ +package ca.uhn.fhir.batch2.coordinator; + +import ca.uhn.fhir.batch2.api.IJobPartitionProvider; +import ca.uhn.fhir.interceptor.model.RequestPartitionId; +import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; +import ca.uhn.fhir.rest.api.server.RequestDetails; + +import java.util.List; + +public class JobPartitionProvider implements IJobPartitionProvider { + protected final IRequestPartitionHelperSvc myRequestPartitionHelperSvc; + + public JobPartitionProvider(IRequestPartitionHelperSvc theRequestPartitionHelperSvc) { + myRequestPartitionHelperSvc = theRequestPartitionHelperSvc; + } + + @Override + public List getPartitions(RequestDetails theRequestDetails, String theOperation) { + RequestPartitionId partitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequestForServerOperation( + theRequestDetails, theOperation); + return List.of(partitionId); + } +} diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProviderTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProviderTest.java new file mode 100644 index 00000000000..2a65f9050d4 --- /dev/null +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobPartitionProviderTest.java @@ -0,0 +1,43 @@ +package ca.uhn.fhir.batch2.coordinator; + +import ca.uhn.fhir.interceptor.model.RequestPartitionId; +import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; +import ca.uhn.fhir.rest.server.provider.ProviderConstants; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class JobPartitionProviderTest { + @Mock + private IRequestPartitionHelperSvc myRequestPartitionHelperSvc; + @InjectMocks + private JobPartitionProvider myJobPartitionProvider; + + @Test + public void getPartitions_requestSpecificPartition_returnsPartition() { + // setup + SystemRequestDetails requestDetails = new SystemRequestDetails(); + String operation = ProviderConstants.OPERATION_EXPORT; + + RequestPartitionId partitionId = RequestPartitionId.fromPartitionId(1); + when(myRequestPartitionHelperSvc.determineReadPartitionForRequestForServerOperation(ArgumentMatchers.eq(requestDetails), ArgumentMatchers.eq(operation))).thenReturn(partitionId); + + // test + List partitionIds = myJobPartitionProvider.getPartitions(requestDetails, operation); + + // verify + Assertions.assertThat(partitionIds).hasSize(1); + Assertions.assertThat(partitionIds).containsExactlyInAnyOrder(partitionId); + } + +} \ No newline at end of file