Skip to content

Conversation

@marko-bekhta
Copy link
Member

https://hibernate.atlassian.net/browse/HSEARCH-5464


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license
and can be relicensed under the terms of the LGPL v2.1 license in the future at the maintainers' discretion.
For more information on licensing, please check here.


@marko-bekhta marko-bekhta force-pushed the feat/HSEARCH-5464-Groundwork-for-pluggable-rest-clients-in-the-Elasticsearch-backend branch 7 times, most recently from aac26ce to 1d41060 Compare September 10, 2025 14:31
@marko-bekhta marko-bekhta force-pushed the feat/HSEARCH-5464-Groundwork-for-pluggable-rest-clients-in-the-Elasticsearch-backend branch 3 times, most recently from 3da3726 to 610c554 Compare September 16, 2025 21:10
@marko-bekhta marko-bekhta force-pushed the feat/HSEARCH-5464-Groundwork-for-pluggable-rest-clients-in-the-Elasticsearch-backend branch 3 times, most recently from e91fd98 to ae10272 Compare October 16, 2025 08:29
Copy link
Member Author

@marko-bekhta marko-bekhta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @yrodiere @lucamolteni 🙂 👋🏻

I've added some comments here and there in this PR in places that may be of interest.
Otherwise there's a lot of "noise", from moving packages and renaming.

This PR doesn't include the docs+migration guide updates. I was thinking about sending that separately, as this already has a lot of changes 🙂.

private final JsonObject body;

public ElasticsearchResponse(HttpHost host, int statusCode, String statusMessage, JsonObject body) {
public ElasticsearchResponse(String host, int statusCode, String statusMessage, JsonObject body) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is pretty straightforward, we only use the host to log the response, and it's an SPI ... so removing the apache class here should be "safe"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're breaking this, it might be a good idea to rename it as well? In particular I see this string includes the port, so it would be more "hostAndPort"

Comment on lines +20 to +23
* https://github.com/google/gson/issues/764 is supposedly fixed.
* Hence, we may not need the workaround anymore.
* This version will be used in the test so we'll notice if things are still broken, for the main code
* the workaround is in place through the GsonProviderHelper.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This GSON issue was fixed, but I kept the workaround for the main code "just in case".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's fixed and we have a non-regression test, I'd say just remove the workaround?

Comment on lines 18 to 21
@SuppressJQAssistant(
reason = "Apache HTTP Client 5 uses a lot of classes/interfaces in the impl packages to create builders/instances etc. "
+ "So while it is bad to expose impl types ... in this case it's what Apache Client expects users to do?")
public interface ElasticsearchHttpClientConfigurationContext {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More of an FYI 🙈

org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ignore Apache HTTP Client 5 classes in the JQAssistant rules instead? If it's really their package naming convention which is at fault.

Comment on lines 67 to 72
if ( entity instanceof AsyncEntityProducer producer ) {
if ( !producer.isRepeatable() ) {
throw new AssertionFailure( "Cannot sign AWS requests with non-repeatable entities" );
}
return new HttpAsyncEntityProducerInputStream( producer, 1024 );
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is a bit annoying as there seems to be no easier/simpler way to get the entity out of the request, but well ... it is what it is 🙂 🤷🏻

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC you copy-pasted the old HttpAsyncContentProducerInputStream two times where you needed it? And possibly other related classes?

This makes me uneasy, because this is very fragile code, and my memories of working with it are... not pleasant ones.

Would it make sense to abstract over the various HTTPD classes (content encoder, ...) and move this code to a single implementation in -utils instead?

*
* @author Sanne Grinovero (C) 2017 Red Hat Inc.
*/
final class GsonHttpEntity implements HttpEntity, AsyncEntityProducer {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the apache client 5 apis changed a bit so these gson entities were updated a bit 🙂
the tests are passing and all seems good, but if anyone would want to have an extra look, that would be nice 🙂

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly doubt anyone can spot mistakes in this code just by reading it. Not a reproach, just an opinion: I've had to deal with this code in the past...

I hope the tests are good :)

@marko-bekhta marko-bekhta force-pushed the feat/HSEARCH-5464-Groundwork-for-pluggable-rest-clients-in-the-Elasticsearch-backend branch from e347a5f to 2e6dca2 Compare October 16, 2025 20:30
Copy link
Member

@yrodiere yrodiere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't review it all but I went through your comments and a bit more, here's what I have to say :)

It's really a shame we can't have a dependency from clients to backend...

This PR doesn't include the docs+migration guide updates. I was thinking about sending that separately, as this already has a lot of changes 🙂.

Since the docs changes would be in very isolated files, you might as well add these changes here :)

Comment on lines +20 to +23
* https://github.com/google/gson/issues/764 is supposedly fixed.
* Hence, we may not need the workaround anymore.
* This version will be used in the test so we'll notice if things are still broken, for the main code
* the workaround is in place through the GsonProviderHelper.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's fixed and we have a non-regression test, I'd say just remove the workaround?

Comment on lines 15 to 18
<artifactId>hibernate-search-backend-elasticsearch-client-java</artifactId>

<name>Hibernate Search Backend - Elasticsearch client based on the low-level Elasticsearch java client</name>
<description>Hibernate Search Elasticsearch client based on the low-level Elasticsearch java client</description>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably rename this, and change the description and dependency, to use that new separate artifact instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 yes, that's the plan, was just waiting for it to get released 👍🏻 🤞🏻 🙂

Comment on lines 18 to 21
@SuppressJQAssistant(
reason = "Apache HTTP Client 5 uses a lot of classes/interfaces in the impl packages to create builders/instances etc. "
+ "So while it is bad to expose impl types ... in this case it's what Apache Client expects users to do?")
public interface ElasticsearchHttpClientConfigurationContext {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ignore Apache HTTP Client 5 classes in the JQAssistant rules instead? If it's really their package naming convention which is at fault.

Comment on lines 15 to 18
<artifactId>hibernate-search-backend-elasticsearch-client-rest</artifactId>

<name>Hibernate Search Backend - Elasticsearch client based on the low-level Elasticsearch client</name>
<description>Hibernate Search Elasticsearch client based on the low-level Elasticsearch client</description>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you know this will disappear at some point, maybe pick a more descriptive name that wouldn't imply "that's how you do rest"? E.g. -rest4 or -rest-apache-http-4?
Good idea for other clients as well, BTW...

private final JsonObject body;

public ElasticsearchResponse(HttpHost host, int statusCode, String statusMessage, JsonObject body) {
public ElasticsearchResponse(String host, int statusCode, String statusMessage, JsonObject body) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're breaking this, it might be a good idea to rename it as well? In particular I see this string includes the port, so it would be more "hostAndPort"

);
}
}
ConfigurationLog.INSTANCE.backendClientFactory( clientFactoryHolder, eventContext.render() );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe pass the eventContext instead of calling render explicitly? That way there's no rendering happening if the log level is filtered out.

See for example

@Message(id = ID_OFFSET_LEGACY_ENGINE + 52,
value = "An index writer operation failed. Resetting the index writer and forcing release of locks. %1$s")
void indexWriterResetAfterFailure(@FormatWith(EventContextFormatter.class) EventContext context);

throw ConfigurationLog.INSTANCE.backendClientFactoryMultipleConfigured(
clientFactoryReferences.stream().map( ref -> ref.resolve( beanResolver ) )
.toList(),
eventContext.render()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can pass the event context directly as a parameter to the exception's constructor, it will behave better.

See for example

@Message(id = ID_OFFSET + 16,
value = "Invalid tenant identifiers: '%1$s'."
+ " No tenant identifier is expected, because multi-tenancy is disabled for this backend.")
SearchException tenantIdProvidedButMultiTenancyDisabled(Set<String> tenantIds, @Param EventContext context);

<version>8.2.0-SNAPSHOT</version>
<relativePath>../../../build/parents/public</relativePath>
</parent>
<artifactId>hibernate-search-backend-elasticsearch-client-opensearch</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't new clients be marked as incubating? "To be safe"? :)

Meaning @Inbucating in APIs/SPIs and an admonition in the docs.

<version>8.2.0-SNAPSHOT</version>
<relativePath>../../../build/parents/public</relativePath>
</parent>
<artifactId>hibernate-search-backend-elasticsearch-client-common</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module even existing feels very wrong... So we really don't have a solution to break circular dependencies between backend and clients?

Some hack to add the dependency from backend to the default client manually, directly in the POM, perhaps?

@marko-bekhta
Copy link
Member Author

Thanks for having a look!

Since the docs changes would be in very isolated files, you might as well add these changes here :)

ohh I already did 🫣 🙂 here:
2e6dca2

at the time I didn't want to prevent anyone from looking at the PR waiting for the docs, but as I had some "free time" since then 😁 I managed to push the change here 😄

@yrodiere
Copy link
Member

I had some "free time"

I envy your time management skills. Honestly.

Copy link
Member

@yrodiere yrodiere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more comments on the docs. Looks great :)

The https://hibernate.org/community/compatibility-policy/#code-categorization[API]
in Hibernate Search {hibernateSearchVersion}
is, in general, backward-compatible with Hibernate Search {hibernateSearchPreviousStableVersionShort}.
But, there are some deprecations:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
But, there are some deprecations:
However, some elements are now deprecated:

Comment on lines 89 to 103
* `org.hibernate.search.backend.elasticsearch.client.ElasticsearchHttpClientConfigurer` is deprecated for removal.
With introduction of the pluggable Elasticsearch backend clients, configurers are a part of the particular client
and expose client-specific configuration knobs.
* `org.hibernate.search.backend.elasticsearch.client.ElasticsearchHttpClientConfigurationContext` is also up for removal,
as it's a part of the configurer API.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe suggest which interface to use for people sticking to the same client? I.e. the simplest migration path.


An Elasticsearch backend communicates with an Elasticsearch cluster through a REST client.
Below are the options that affect this client.
Hibernate Search comes with a range of pluggable Elasticsearch REST clients that the user can pick from:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"User" means something different for us and for... our users.

Suggested change
Hibernate Search comes with a range of pluggable Elasticsearch REST clients that the user can pick from:
Hibernate Search comes with a range of pluggable Elasticsearch REST clients that you can pick from:

or

Suggested change
Hibernate Search comes with a range of pluggable Elasticsearch REST clients that the user can pick from:
Hibernate Search comes with a range of pluggable Elasticsearch REST clients that applications can pick from:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add something to the "Artifacts" section, mentioning that applications should explicitly depend on the client they want to use, if they do care about which client is used?

@marko-bekhta marko-bekhta force-pushed the feat/HSEARCH-5464-Groundwork-for-pluggable-rest-clients-in-the-Elasticsearch-backend branch 7 times, most recently from 12e8879 to d4e3fce Compare October 25, 2025 20:26
@marko-bekhta marko-bekhta force-pushed the feat/HSEARCH-5464-Groundwork-for-pluggable-rest-clients-in-the-Elasticsearch-backend branch from d4e3fce to b805101 Compare October 25, 2025 21:07
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
71.4% Coverage on New Code (required ≥ 80%)
18.6% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants