Hi all,
I have a question about the multitenancy and hibernate search. I running a spring boot application (spring boot 2.2.4, hibernate search 6.0.0 and elasticsearch 7.4)
i have create a class that extends HandlerInterceptorAdapter for spring to determine the tenant from the httpRequest, i stock that in a thread local. i have implemented a class with MultiTenantConnectionProvider to switch the schema and override the 2 methodes : getConnection(String tenant). releaseConnection(String tenantIdentifier, Connection connection).
if my thread local have a tenant identifier that mean that i’m comme from a http request and i switch the tenant. With that i have create a entry point to reindex a tenant with hibernate search. If i call my entry point for each tenant elasticsearch index all data with tenant discriminator. -> Works !
If i launch my method with a @Scheduled(cron="") annotation i don’t come from a http request and hibernatesearch only index the default tenant. I create a loop to set like inside my httpinterceptor and set the tenant inside the thread local. the indexation is totaly random and the tenant resolver don’t work.
How can i set the tenant to hibernate search to index the correct tenant ?
Thank’s
With debugging i see that the getConnection method is called before start scheduled annoted method. I can set a tenant in my ThreadLocal, that not works because the connection is already set to an another tenant.
Hibernate Search does not do much when it comes to tenant identifiers:
- during automatic indexing or when searching, it just gets the tenant identifier from the Hibernate ORM Session, and uses that for indexing and searching.
- during mass indexing, it systematically opens a new session for entity loading, and tells Hibernate ORM to use the tenant ID that was detected when creating the mass indexer.
If something doesn’t work when mass indexing, it’s either because:
- you create your mass indexer from a session and the tenant ID is not detected correctly (
Session.getTenantIdentifier()
returns null
, for example)
- OR the connection provider somehow doesn’t understand the tenant ID correctly
I’d bet on #1, but who knows.
When mass indexing, you can simply use this to set the tenant identifier explicitly:
// Inject this into your bean somehow
EntityManagerFactory entityManagerFactory;
for ( String tenantId : allTenantIds ) {
MassIndexer massIndexer = Search.mapping( entityManagerFactory ).scope( Object.class )
.massIndexer( tenantId );
// ...
}
Maybe that helps?
Hi yann,
Thank’s for this reply. I don’t see the search scope inside the documentation. I have a question about this, if i set a tenantId on the massIndexer parameter, we don’t care about the current tenant Id of the entityManager provide by spring ? ex : if my request come from the default tenant but i want to reindex the tenant1. I don’t care about the tenant set inside requestParam of the spring/hibernate. hibernatesearch set himself the tenant and make the job ?
Alexis
Right. Whatever you pass manually has precedence over what’s in your session. That’s because mass indexing is considered an administrative operation, not something you’d do in a “business” method.
I don’t know what your requestParam
is, but if you pass “tenant1” when you create the mass indexer, then yes, “tenant1” is the one that will be reindexed. Hibernate Search will internally create sessions for “tenant1” to load entities. The original session will not be used for mass indexing.