opened
jkirsch
username_0
This is a feature request.

Using an embedded instance of elastic search that should be used by hibernate search in a spring boot autoconfigured environment exhibits a race condition.
Elastic search starts in the background and when hibernate gets initialized it tries to connect to elastic search, which it is not up yet, thus the app fails to start.

How to reproduce

Using spring boot `1.4.0.M3` and the following additional JPA dependencies. Assuming `@Field` annotations on the jpa entity classes.

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <version>1.4.0.M3</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
        <artifactId>hibernate-search-backend-elasticsearch</artifactId>
        <version>5.6.0.Alpha3</version>
</dependency
```
Using the following properties

```
spring.data.elasticsearch.properties.http.enabled= true
spring.jpa.properties.hibernate.search.default.indexmanager= elasticsearch
```

It only works, when `index_management_strategy` is set to [none](https://github.com/hibernate/hibernate-search/blob/f78306e8c5b1b8efe6069aa129af5fcb58f045fb/documentation/src/main/asciidoc/elasticsearch-integration.asciidoc#configuration) which skips the initial index configuration. But this means during hibernate setup nothing is send to elastic search, only later when new entities are created. At that time elastic search has finished loading and it works. But unfortunately, because no index has been configured, it uses the default index, which cannot be configured from the properties, thus misses any special `Analyzer` or `Tokenizer` set on the entity classes.

### Why would one want that?
It is nice to configure everything together for integration tests. Furthermore, I'm deploying as a fat jar into openshift, so having only one jar to manage eases deployment - instead of starting elastic search separately.

### The problem
The problem comes from the background initialization of elastic search, it finishes initialization, even though its not up yet.

### How to solve
Not sure, I posted the question on [stackoverflow](http://stackoverflow.com/questions/37930019/spring-boot-hibernate-search-elastic-search-embedded-fails-to-start) without success.
Potentially there should be some form of a busy wait on elastic search being up (responds to host:9200) during the autoconfiguration process
Better support for hibernate search with embedded elastic search
issue
created
wilkinsona
username_1
@username_0 Can you please provide a small sample that reproduces the problem? I've tried modifying our Data JPA sample but have been unable to cause it to fail to start.
comment
created
jkirsch
username_0
Sure, 
I'll look into it. To get it to fail, one needs to set the `index_management_strategy` to for example `CREATE_DELETE`
`spring.jpa.properties.hibernate.search.default.indexmanager.elasticsearch=CREATE_DELETE`
comment
created
jkirsch
username_0
Please find attached a small demo project, that exhibits the problem

[demo.zip](https://github.com/spring-projects/spring-boot/files/350664/demo.zip)

I also upgraded to spring boot 1.4 RC1, but it has the same error.
comment
created
wilkinsona
username_1
@username_0 Thanks for the sample, I've now reproduced the problem.
comment
created
wilkinsona
username_1
There's no race condition here as far as I can tell, it's a simple ordering problem.

The problem is that there's no dependency between the `EntityManagerFactory` bean and the Elasticsearch `Client` bean so there's no guarantee that Elasticsearch will start before Hibernate. As it happens, Hibernate starts first and then fails to connect to Elasticsearch. 

This can be fixed by setting up a dependency between the two beans. An easy way to do that is with a subclass of `EntityManagerFactoryDependsOnPostProcessor`:

```java
@Configuration
static class ElasticsearchJpaDependencyConfiguration extends EntityManagerFactoryDependsOnPostProcessor {

	public ElasticsearchJpaDependencyConfiguration() {
		super("elasticsearchClient");
	}

}
```

With this change in place, Elasticsearch starts before Hibernate. Unfortunately, there's still a failure:

```
Caused by: org.hibernate.search.exception.SearchException: HSEARCH400007: Elasticsearch request failed.
 Request:
========
Operation: 
Data:
null
Response:
=========
Status: 408
Error message: 408 Request Timeout


	at org.hibernate.search.backend.elasticsearch.client.impl.JestClient.executeRequest(JestClient.java:89) ~[hibernate-search-backend-elasticsearch-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.backend.elasticsearch.client.impl.JestClient.executeRequest(JestClient.java:80) ~[hibernate-search-backend-elasticsearch-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchIndexManager.waitForIndexCreation(ElasticsearchIndexManager.java:189) ~[hibernate-search-backend-elasticsearch-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchIndexManager.createIndex(ElasticsearchIndexManager.java:174) ~[hibernate-search-backend-elasticsearch-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchIndexManager.initializeIndex(ElasticsearchIndexManager.java:154) ~[hibernate-search-backend-elasticsearch-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchIndexManager.setSearchFactory(ElasticsearchIndexManager.java:143) ~[hibernate-search-backend-elasticsearch-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.indexes.impl.IndexManagerHolder.setActiveSearchIntegrator(IndexManagerHolder.java:188) ~[hibernate-search-engine-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.engine.impl.MutableSearchFactoryState.setActiveSearchIntegrator(MutableSearchFactoryState.java:225) ~[hibernate-search-engine-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.spi.SearchIntegratorBuilder.buildNewSearchFactory(SearchIntegratorBuilder.java:226) ~[hibernate-search-engine-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.spi.SearchIntegratorBuilder.buildSearchIntegrator(SearchIntegratorBuilder.java:117) ~[hibernate-search-engine-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.search.hcore.impl.HibernateSearchSessionFactoryObserver.sessionFactoryCreated(HibernateSearchSessionFactoryObserver.java:75) ~[hibernate-search-orm-5.6.0.Alpha3.jar:5.6.0.Alpha3]
	at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:35) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:530) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final]
	... 21 common frames omitted
```

`ElasticsearchIndexManager.waitForIndexCreation` waits for the health to be green. With the configuration in the sample application it only ever reaches yellow:

```
2016-07-07 13:14:13.806  INFO 15865 --- [pdateTask][T#1]] org.elasticsearch.cluster.metadata       : [Freedom Ring] [com.example.model.person] creating index, cause [api], templates [], shards [5]/[1], mappings []
2016-07-07 13:14:13.848  INFO 15865 --- [pdateTask][T#1]] o.e.cluster.routing.allocation           : [Freedom Ring] Cluster health status changed from [RED] to [YELLOW] (reason: [shards started [[com.example.model.person][4]] ...]).
```

I don't know enough about Elasticsearch and Hibernate Search to know why the cluster doesn't become green. In our Elasticsearch sample the cluster does become green so I suspect it's a side-effect of how Hibernate Search configures Elasticsearch.

@username_0 Does this give you what enough to get things going?
comment
created
jkirsch
username_0
Thanks so much for looking into this.
Indeed the ordering constraint is what I was looking for, as originally described on stack overflow - didn't know there is such a simple fix available.

I updated the sample and was able to run it.

The reason for status yellow, is that there are no replicas defined in the cluster [doc](https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html) . Which is understandable, as this is a single node deployment.

This can be easily fixed, by setting the number of replicas to `0` instead of the default `1`

```properties
spring.data.elasticsearch.properties.index.number_of_replicas=0
```

Feels like this should be documented somewhere. 
Once more, thanks for quickly looking into this :+1:
comment
created
philwebb
username_2
@username_1 I'm tempted to add `ElasticsearchJpaDependencyConfiguration` into 1.4. What do you think?
comment
created
wilkinsona
username_1
I'm not sure... It's only necessary when Hibernate Search is being used and it's configured to use Elasticsearch as its index manager. I wonder if it's possible that setting up the dependency would do some harm when that's not the case? I can't think of a case where it would, but I'm a bit wary as I can recall a problem with one of the caches we support where it can either depend on Hibernate or Hibernate can depend on it depending on how it's being used.
comment
created
philwebb
username_2
OK, we'll just make add a general HowTo about `EntityManagerFactoryDependsOnPostProcessor` and use this as the example.
comment
closed
wilkinsona
username_1
issue