Hibernate Search: отключение проверки доступности кластера Elasticsearch при запуске приложения
Понадобилось нам тут реализовать отказоустойчивое поведение приложения в случае недоступности внешних сервисов, одним из которых являлся кластер Elasticsearch.
Для работы с ним мы используем Hibernate Search и используем лишь малую его часть — нам просто необходимо строить индекс, а затем делать к нему обращения во время набора текста в определённых полях на UI. То есть своеобразная подстановка значений по типу "search-as-you-type". Связи индекса с вводимыми пользователем где-то в приложении значениями нет, то есть можно грубо сказать что он живёт отдельной жизнью.
Итак, если попытаться запустить приложение без необходимых модификаций и с недоступным Elasticsearch, можно увидеть примерно следующее сообщение об ошибке:
HSEARCH400080: Unable to detect the Elasticsearch version running on the cluster: HSEARCH400007: Elasticsearch request failed: The requested name is valid, but no data of the requested type was found (eslb.*.ru)
Первым делом появляется вариант отключения этой проверки версии на старте. И возможно появляется вариант отключения всей интеграции с Elasticsearch, а в случае когда он будет доступен — инициализации. Так вот это вообще не вариант. Да, действительно, отключить интеграцию с Hibernate Search можно через задание параметра hibernate.search.enabled
= false, но отключив его таким образом на этапе запуска приложения, потом, во время жизненного цикла, Search уже так просто назад не включится.
Этот вариант нам совсем не подходит.
Переходим к документации и находим раздел "11.4.8 Version" в котором говорится, что для того, чтобы выключить проверку версии при запуске, необходимо задать 2 параметра:
hibernate.search.backend.version_check.enabled
= falsehibernate.search.backend.version
(достаточно первых 2 цифр)
Добавляем в наш application.yml:
spring: jpa: properties: hibernate: search: backend: version: 7.8 version_check: enabled: false
Пробуем выполнить запуск, снова ошибка:
HSEARCH400034: Unable to retrieve index metadata from Elasticsearch: HSEARCH400007: Elasticsearch request failed: The requested name is valid, but no data of the requested type was found (eslb.dev.ppod.cbr.ru)
На этот раз связана она с тем, что при инициализации Hibernate Search пытается узнать что делать с индексами и их схемами. Для того, чтобы изменить это поведение, необходимо установить параметр hibernate.search.schema_management.strategy
:
spring: jpa: properties: hibernate: search: schema_management: strategy: none
После таких манипуляций приложение будет запускаться и не падать вне зависимости от доступности кластера Elasticsearch, однако индексация и управление её схемой работать не будет.
Для того, чтобы восстановить работу этих компонентов можно пойти двумя путями:
- Выполнить индексацию руками
- Попросить Hibernate Search запустить индексацию, когда Elasticsearch станет доступен
Пойдя по второму пути развития событий можно привести в пример следующий код:
log.info("Начало индексации"); SearchSession searchSession = Search.session(entityManager); SearchSchemaManager schemaManager = searchSession.schemaManager(); schemaManager.createOrValidate(); searchSession.massIndexer(HistoryRecords.class) .batchSizeToLoadObjects(BATCH_SIZE) .startAndWait(); log.info("Индексация закончена успешно");
Здесь мы задали SearchSchemaManager и установили для него необходимую нам стратегию работы с индексами (и их схемами) -- create or validate
. Стоит помнить, что если в случае вызова данного кода кластер Elasticsearch недоступен, приложение выдаст закономерную ошибку.
Итак, подводя итог вышесказанному можно сказать следующее.
Для того, чтобы модуль, который использует Hibernate Search не падал при запуске в случае недоступности кластера Elasticsearch, необходимо:
- явно указать версию Elasticsearch и отключить её проверку при запуске
- отключить автоматическое управление схемой и индексами
- вручную запустить управление схемой и индексами как только кластер Elasticsearch станет доступен
Решение очень простое, но для более сложных use-case не подойдёт (в случае когда изменения в БД предполагают последующие обновления в индексе). Для того, чтобы обрабатывать и такие ситуации, необходимо обратиться к outbox-polling coordination strategy. Она позволит сохранять события изменений entity в БД и асинхронно обрабатывать их в фоновом потоке. Также для работы этого функционала необходимо сообщить Hibernate Search повторить неудавшиеся события как только Elasticsearch станет доступен. Outbox polling coordination strategy — неплохой вариант, но у него есть свои плюсы и минусы с которыми можно ознакомиться здесь.
В целом — это всё, что хотел рассказать по этой теме сегодня. Планировал написать небольшую статью, но получилось опять достаточно обширно.