Open ricardofago opened 2 years ago
Heya @ricardofago , no you should not have those errors at boot time with a fresh database. I'll see if I can replicate this. If you could make bulleted replication steps (and let me know which branch you're on for hapi-fhir-jpaserver-starter) that would be helpful.
Hi @tadgh, I've been out of the loop for a while but it should be easy to replicate. I was trying a new setup, so something like that:
datasource:
#url: 'jdbc:h2:file:./target/database/h2'
url: jdbc:h2:mem:test_mem
mdm_enabled: true
partitioning:
allow_references_across_partitions: true
partitioning_include_in_search_hashes: false
package custom.package;
import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.interceptor.api.Hook; import ca.uhn.fhir.interceptor.api.Interceptor; import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.model.RequestPartitionId; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.tenant.ITenantIdentificationStrategy; import org.hl7.fhir.dstu2016may.model.Enumerations;
import javax.annotation.Nonnull;
import java.util.Arrays; import java.util.List;
import static org.apache.commons.lang3.StringUtils.isBlank;
/**
@see HeaderTenantIdentificationStrategy */ @Interceptor public class HapiTenantPartitionInterceptor {
/**
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE) public RequestPartitionId PartitionIdentifyCreate(RequestDetails theRequestDetails) { if (NON_PARTITIONABLE_RESOURCES.contains(theRequestDetails.getResourceName())) { return RequestPartitionId.defaultPartition(); } else { return extractPartitionIdFromRequest(theRequestDetails); } }
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ) public RequestPartitionId PartitionIdentifyRead(RequestDetails theRequestDetails) { if (NON_PARTITIONABLE_RESOURCES.contains(theRequestDetails.getResourceName())) { return RequestPartitionId.defaultPartition(); } else { return extractPartitionIdFromRequest(theRequestDetails); } }
@Nonnull protected RequestPartitionId extractPartitionIdFromRequest(RequestDetails theRequestDetails) {
// We will use the tenant ID that came from the request as the partition name
String tenantId = theRequestDetails.getTenantId();
if (isBlank(tenantId)) {
throw new InternalErrorException(Msg.code(343) + "No tenant ID has been specified");
}
return RequestPartitionId.fromPartitionName(tenantId);
}
}
```java
package custom.package;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.tenant.ITenantIdentificationStrategy;
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
import ca.uhn.fhir.util.UrlPathTokenizer;
import org.apache.commons.lang3.Validate;
import org.h2.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
/**
* This class is a tenant identification strategy which assumes that a custom
* HTTP header <tt>X-HAPI-Tenant</tt> will be present in the actual request.
* Otherwise, the tenant is assumed to be the default one.
* <p>The goal is to enable a tenancy environment which relies on additional
* middleware infrastructure to keep the standard FHIR interaction flow.</p>
*/
public class HeaderTenantIdentificationStrategy implements ITenantIdentificationStrategy {
private static final Logger ourLog = LoggerFactory.getLogger(HeaderTenantIdentificationStrategy.class);
@Override
public void extractTenant(UrlPathTokenizer theUrlPathTokenizer, RequestDetails theRequestDetails) {
String tenantId = theRequestDetails.getHeader("X-HAPI-Tenant");
if (StringUtils.isNullOrEmpty(tenantId)) {
tenantId = "DEFAULT";
ourLog.debug("X-HAPI-Tenant not present in request, assuming DEFAULT");
} else {
ourLog.debug("X-HAPI-Tenant present in request, tenant ID = {}", tenantId);
}
theRequestDetails.setTenantId(tenantId);
}
@Override
public String massageServerBaseUrl(String theFhirServerBase, RequestDetails theRequestDetails) {
return theFhirServerBase;
}
}
if (appProperties.getPartitioning() != null) {
registerInterceptor(new custom.package.HapiTenantPartitionInterceptor());
setTenantIdentificationStrategy(new custom.package.HeaderTenantIdentificationStrategy());
registerProviders(partitionManagementProvider);
}
I'm not sure the custom classes are required for the test, we use header-based tenant identification to update deployments that aren't yet fully partition aware by keeping the URLs backwards compatible, but I believe they helped tracking down the inner issues I mentioned. The weird thing if I remember correctly was that during the initialization it was crashing for something related to Subscription within MDM without triggering the pointcuts/tenant ID resolution.
Thanks Ricardo, I'll have a look at this the moment i get back from vacation
Hi everyone!
I've been experimenting with the latest HAPI FHIR releases to test the update process and it seems to crash due to to something in the recent Subscription and MDM changes. From my limited debugging, it gets to https://github.com/hapifhir/hapi-fhir/blob/b0020a296fa6b0e0f62dce1cd63b43c94cec1b88/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java#L114 (default tenant) properly for some initial system calls (SearchParameter, Subscription), registers the partition interceptor and the identification strategy for multi-tenancy, but then it seems to crash at another Subscription related call during the MDM stuff without ever calling the STORAGE_PARTITION_IDENTIFY_READ pointcut in https://github.com/hapifhir/hapi-fhir/blob/b0020a296fa6b0e0f62dce1cd63b43c94cec1b88/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java#L127, even if I hardcode the tenant ID. This actually prevents the JPA server from starting, but only happens if
mdm_enabled: true
.This can be reproduced in v5.7.0 (and previous recent releases) using the JPA server with the standard settings plus enabling multi-tenancy and MDM. It not familiar with the internals of the MDM code but I'm guessing there's something preventing the Subscription request from falling back to the default tenant ID. Around the first exception I have:
Perhaps, more specifically:
Does it make sense to have those issues while starting a fresh install using the in-memory H2 database? Here's the environment:
Thank you very much!