【问题标题】:Spring Boot Integration Test failes due to lucene lock when using Hibernate Search使用 Hibernate Search 时,由于 lucene 锁定,Spring Boot 集成测试失败
【发布时间】:2018-03-13 09:01:07
【问题描述】:

在我的 Spring Boot 1.5.10.Final 项目中,我使用 Hibernate Search ORM 5.6.4.Final。除了集成测试外,它工作正常。一个测试班有几个 测试方法来测试搜索逻辑。如果我只运行这个测试类,一切都很好。 Spring Boot 正在启动并创建索引。如果我运行这个测试类 与所有其他集成测试一起,每个测试类都会抛出 LockObtainFailedException 并且 Hibernate Search 测试将失败。

org.apache.lucene.store.LockObtainFailedException: Lock held by this virtual machine: ...LieferantEntity\write.lock
    at org.apache.lucene.store.NativeFSLockFactory.obtainFSLock(NativeFSLockFactory.java:127) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
    at org.apache.lucene.store.FSLockFactory.obtainLock(FSLockFactory.java:41) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
    at org.apache.lucene.store.BaseDirectory.obtainLock(BaseDirectory.java:45) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
    at org.apache.lucene.index.IndexWriter.<init>(IndexWriter.java:776) ~[lucene-core-5.5.5.jar:5.5.5 b3441673c21c83762035dc21d3827ad16aa17b68 - sarowe - 2017-10-20 08:57:09]
    at org.hibernate.search.backend.impl.lucene.IndexWriterHolder.createNewIndexWriter(IndexWriterHolder.java:126) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.search.backend.impl.lucene.IndexWriterHolder.getIndexWriter(IndexWriterHolder.java:92) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.search.backend.impl.lucene.AbstractWorkspaceImpl.getIndexWriter(AbstractWorkspaceImpl.java:117) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.search.backend.impl.lucene.AbstractWorkspaceImpl.getIndexWriterDelegate(AbstractWorkspaceImpl.java:203) ~[hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.search.backend.impl.lucene.LuceneBackendQueueTask.applyUpdates(LuceneBackendQueueTask.java:81) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.search.backend.impl.lucene.LuceneBackendQueueTask.run(LuceneBackendQueueTask.java:46) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.search.backend.impl.lucene.SyncWorkProcessor$Consumer.applyChangesets(SyncWorkProcessor.java:165) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at org.hibernate.search.backend.impl.lucene.SyncWorkProcessor$Consumer.run(SyncWorkProcessor.java:151) [hibernate-search-engine-5.6.4.Final.jar:5.6.4.Final]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]

我使用默认设置。如果我将 Exclusive_index_use 设置为 false,则它可以正常工作,但测试执行速度非常慢。 对我来说,索引似乎是在 Spring Boot 启动期间初始化的,并且会干扰测试。

是否可以通过 Hibernate Search 使用 Spring Boot 集成测试,以便在测试之间干净地释放锁? 或者,我正在寻找一种方法来禁用所有不使用 Hibernate Search 的集成测试的 Hibernate Search 索引

我也已经尝试过近实时的属性和不同的锁工厂作为原生、简单和单一但没有运气。

【问题讨论】:

    标签: spring-boot hibernate-search spring-boot-test


    【解决方案1】:

    首先:除非您是 Lucene 大师,否则不要使用 exclusive_index_use。这很危险,可能不会按照您的意愿行事。

    现在我们已经解决了这个问题……据我了解,您正在尝试在同一台机器上并行执行集成测试。这意味着集成测试可能会竞争访问完全相同的索引,并将写入相同的索引。如果您的测试执行冲突写入(一个测试在该测试完成之前擦除另一个测试添加的文档),这可能会导致不可预知的结果。

    如果您确实需要并行执行测试,我建议您在隔离环境中执行每个测试:

    • 专用数据库,或至少专用数据库架构
    • 专用 Lucene 索引
    • 等

    在 Hibernate Search 的情况下,您必须想办法在每次测试执行中使用不同的物理索引。

    有两种方法可以做到这一点:

    1. 仅用于测试,不要将索引存储在文件系统中,而是直接存储在堆中,方法是将hibernate.search.backend.directory.type 设置为local-heap(Hibernate Search 6+)或将hibernate.search.default.directory_provider 设置为local-heap(Hibernate Search 5 和下面)。

    它非常容易实现,但您应该注意一些缺点:

    • 您的测试环境将不再与您的生产环境完全相同
    • 测试完成后索引将丢失,这可能会使事后调试变得困难(您将无法再使用 Luke 检查索引的状态)
    • 如果您的集成测试在索引中存储了大量内容,您可能会收到OutOfMemoryError。
    1. 如果解决方案 1 的缺点对您来说太多,您可以继续使用文件系统来存储索引,但每次测试执行使用不同的配置,设置索引基本路径(hibernate.search.backend.directory.root 用于 Hibernate Search 6+ ,或 hibernate.search.default.indexBase 用于 Hibernate Search 5 及更低版本)到每个测试执行的一些唯一路径。您将不得不在 Spring 中找到如何做到这一点,但我会惊讶地发现这是不可能的。也许 Spring 允许您在属性中使用插值,例如 hibernate.search.backend.directory.root = /tmp/it/#{testName}?

    有关如何配置索引存储的详细信息,请参阅有关目录配置的文档(here for Hibernate Search 6+ 或 here for Hibernate Search 5。

    【讨论】:

    • 我同意使用local-heap,它是为这样的测试需求而设计的:简单并且避免磁盘写入。只要确保不要像 Yoann 建议的那样在其中写入太多数据。
    • hibernate.search.default.directory_provider = ram 正是我想要的。 @yoannrodière 感谢您的详细解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    • 2017-07-02
    • 2020-03-18
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    相关资源
    最近更新 更多