Skip to content

Commit

Permalink
Merge pull request #16655 from yrodiere/start_offline
Browse files Browse the repository at this point in the history
Hibernate Search: Add configuration property to skip the Elasticsearch version check
  • Loading branch information
gsmet authored Apr 20, 2021
2 parents 98bf638 + 239858f commit 2cbd177
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 6 deletions.
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

0 comments on commit 2cbd177

Please sign in to comment.