Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hibernate Search: Add configuration property to skip the Elasticsearch version check #16655

Merged
merged 5 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion docs/src/main/asciidoc/hibernate-search-orm-elasticsearch.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ Entities are attached to a persistence unit by
link:hibernate-orm#multiple-persistence-units-attaching-model-classes[configuring the Hibernate ORM extension].

[[multiple-persistence-units-attaching-cdi]]
=== CDI integration
== CDI integration

You can inject Hibernate Search's main entry points, `SearchSession` and `SearchMapping`, using CDI:

Expand Down Expand Up @@ -762,6 +762,35 @@ We also inject some data and execute the mass indexer.
In a real life application, it is obviously something you won't do at startup.
====

[[offline-startup]]
== Offline startup

By default, Hibernate Search sends a few requests to the Elasticsearch cluster on startup.
If the Elasticsearch cluster is not necessarily up and running when Hibernate Search starts,
this could cause a startup failure.

To address this, you can configure Hibernate Search to not send any request on startup:

* Disable Elasticsearch version checks on startup by setting the configuration property
link:#quarkus-hibernate-search-orm-elasticsearch_quarkus.hibernate-search-orm.elasticsearch.version-check.enabled[`quarkus.hibernate-search-orm.elasticsearch.version-check.enabled`]
to `false`.
* Disable schema management on startup by setting the configuration property
link:#quarkus-hibernate-search-orm-elasticsearch_quarkus.hibernate-search-orm.schema-management.strategy[`quarkus.hibernate-search-orm.schema-management.strategy`]
to `none`.

Of course, even with this configuration, Hibernate Search still won't be able to index anything or run search queries
until the Elasticsearch cluster becomes accessible.

[IMPORTANT]
====
If you disable automatic schema creation by setting `quarkus.hibernate-search-orm.schema-management.strategy` to `none`,
you will have to create the schema manually at some point before your application starts persisting/updating entities
and executing search requests.

See link:{hibernate-search-doc-prefix}#mapper-orm-schema-management-manager[this section of the reference documentation]
for more information.
====

== Further reading

If you are interested in learning more about Hibernate Search 6,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.quarkus.hibernate.search.elasticsearch.test.offline;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;

@Entity
@Indexed
public class IndexedEntity {

@Id
@GeneratedValue
public Long id;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.quarkus.hibernate.search.elasticsearch.test.offline;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import javax.inject.Inject;
import javax.transaction.Transactional;

import org.hibernate.search.mapper.orm.entity.SearchIndexedEntity;
import org.hibernate.search.mapper.orm.mapping.SearchMapping;
import org.hibernate.search.mapper.orm.session.SearchSession;
import org.hibernate.search.util.common.SearchException;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;

/**
* Test that an application can be configured to start successfully
* even if the Elasticsearch cluster is offline when the application starts.
*/
public class StartOfflineTest {

@RegisterExtension
static QuarkusUnitTest runner = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(IndexedEntity.class)
.addAsResource("application-start-offline.properties", "application.properties"));

@Inject
SearchMapping searchMapping;

@Inject
SearchSession searchSession;

@Test
public void testHibernateSearchStarted() {
assertThat(searchMapping.allIndexedEntities())
.hasSize(1)
.element(0)
.returns(IndexedEntity.class, SearchIndexedEntity::javaClass);
}

@Test
@Transactional
public void testSchemaManagementAvailableButFailsSinceElasticsearchNotStarted() {
assertThatThrownBy(() -> searchSession.schemaManager(IndexedEntity.class).createIfMissing())
.isInstanceOf(SearchException.class)
.hasMessageContaining("Elasticsearch request failed: Connection refused");
}

@Test
@Transactional
public void testSearchAvailableButFailsSinceElasticsearchNotStarted() {
assertThatThrownBy(() -> searchSession.search(IndexedEntity.class)
.where(f -> f.matchAll()).fetchHits(20))
.isInstanceOf(SearchException.class)
.hasMessageContaining("Elasticsearch request failed: Connection refused");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1

quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
quarkus.hibernate-orm.database.generation=drop-and-create

quarkus.hibernate-search-orm.elasticsearch.version=7.10
# Simulate an offline Elasticsearch instance by pointing to a non-existing cluster
quarkus.hibernate-search-orm.elasticsearch.hosts=localhost:14800
quarkus.hibernate-search-orm.schema-management.strategy=none
quarkus.hibernate-search-orm.elasticsearch.version-check.enabled=false
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ public static class ElasticsearchBackendBuildTimeConfig {
@ConfigItem
public Optional<ElasticsearchVersion> version;

// TODO This should be a runtime property, but we need https://hibernate.atlassian.net/browse/HSEARCH-4214 fixed
/**
* Whether Hibernate Search should check the version of the Elasticsearch cluster on startup.
* <p>
* Set to {@code false} if the Elasticsearch cluster may not be available on startup.
*/
@ConfigItem(name = "version-check.enabled", defaultValue = "true")
public boolean versionCheck;

/**
* Configuration for the index layout.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import javax.enterprise.inject.literal.NamedLiteral;

import org.graalvm.home.Version;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
Expand Down Expand Up @@ -112,8 +111,6 @@ public void onMetadataInitialized(Metadata metadata, BootstrapContext bootstrapC
private static final class HibernateSearchIntegrationStaticInitListener
implements HibernateOrmIntegrationStaticInitListener {

private static final Version GRAAL_VM_VERSION_21 = Version.create(21);

private final HibernateSearchElasticsearchBuildTimeConfigPersistenceUnit buildTimeConfig;

private HibernateSearchIntegrationStaticInitListener(
Expand Down Expand Up @@ -151,6 +148,8 @@ private void contributeBackendBuildTimeProperties(BiConsumer<String, Object> pro
ElasticsearchBackendSettings.TYPE_NAME);
addBackendConfig(propertyCollector, backendName, ElasticsearchBackendSettings.VERSION,
elasticsearchBackendConfig.version);
addBackendConfig(propertyCollector, backendName, ElasticsearchBackendSettings.VERSION_CHECK_ENABLED,
elasticsearchBackendConfig.versionCheck);
addBackendConfig(propertyCollector, backendName,
ElasticsearchBackendSettings.LAYOUT_STRATEGY,
elasticsearchBackendConfig.layout.strategy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,67 @@ public static class SearchQueryLoadingCacheLookupConfig {
@ConfigGroup
public static class SchemaManagementConfig {

// @formatter:off
/**
* The strategy used for index lifecycle.
* The schema management strategy, controlling how indexes and their schema
* are created, updated, validated or dropped on startup and shutdown.
*
* Available values:
*
* [cols=2]
* !===
* h!Strategy
* h!Definition
*
* !none
* !Do nothing: assume that indexes already exist and that their schema matches Hibernate Search's expectations.
*
* !validate
* !Validate that indexes exist and that their schema matches Hibernate Search's expectations.
*
* If it does not, throw an exception, but make no attempt to fix the problem.
*
* !create
* !For indexes that do not exist, create them along with their schema.
*
* For indexes that already exist, do nothing: assume that their schema matches Hibernate Search's expectations.
*
* !create-or-validate (**default**)
* !For indexes that do not exist, create them along with their schema.
*
* For indexes that already exist, validate that their schema matches Hibernate Search's expectations.
*
* If it does not, throw an exception, but make no attempt to fix the problem.
*
* !create-or-update
* !For indexes that do not exist, create them along with their schema.
*
* For indexes that already exist, validate that their schema matches Hibernate Search's expectations;
* if it does not match expectations, try to update it.
*
* **This strategy is unfit for production environments**,
* due to several important limitations,
* but can be useful when developing.
*
* !drop-and-create
* !For indexes that do not exist, create them along with their schema.
*
* For indexes that already exist, drop them, then create them along with their schema.
*
* !drop-and-create-and-drop
* !For indexes that do not exist, create them along with their schema.
*
* For indexes that already exist, drop them, then create them along with their schema.
*
* Also, drop indexes and their schema on shutdown.
* !===
*
* See https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#mapper-orm-schema-management-strategy[this section of the reference documentation]
* for more information.
*
* @asciidoclet
*/
// We can't set an actual default value here: see comment on this class.
// @formatter:on
@ConfigItem(defaultValue = "create-or-validate")
SchemaManagementStrategyName strategy;

Expand Down