Spring 引导集成测试在使用休眠搜索时由于 lucene 锁定而失败



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

org.apache.lucene.store.LockObtainFailedException: Lock held by this virtual machine: ...LieferantEntitywrite.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 启动期间初始化的,并且在测试之间干扰。

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

我也已经尝试了该物业近乎实时和不同的锁工厂作为本地,简单和单一没有运气。

首先:不要使用exclusive_index_use,除非你是Lucene大师。这是危险的,可能不会按照你想要的方式行事。

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

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

专用数据库
  • ,或至少是专用数据库架构
  • 专用卢西尼指数
  • 等。

在Hibernate搜索的情况下,您必须找到一种方法在每次测试执行中使用不同的物理索引。

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

  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 6+ 为hibernate.search.backend.directory.root,或 Hibernate Search 5 及更低版本为hibernate.search.default.indexBase)设置为每个测试执行的某个唯一路径。你必须在春天找到如何做到这一点,但我会惊讶地发现这是不可能的。也许 Spring 允许您在属性中使用插值,例如hibernate.search.backend.directory.root = /tmp/it/#{testName}

有关如何配置索引存储的详细信息,请参阅有关目录配置的文档(此处适用于 Hibernate Search 6+,此处适用于 Hibernate Search 5)。

最新更新