【发布时间】:2019-06-13 12:01:58
【问题描述】:
在一些自动化测试中,我尝试在每次测试开始时删除并立即重新创建一个索引,使用 ElasticSearch 的高级休息客户端(版本 6.4),如下所示:
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
deleteIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
request.mapping("_doc", "{...}", XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);
我遇到的问题是,我的测试间歇性地在创建索引时失败,并出现错误:
{"error": {"root_cause":[{"type":"resource_already_exists_exception","reason":"index [(index-name)/(UUID)] already exists, ...,}] "status":400}
我运行的测试越多,我就越有可能看到错误,这似乎是一个强有力的指标,表明这是一个竞争条件 - 大概当我尝试重新创建索引时,之前的删除操作并不总是完成.
如果我在删除操作后立即设置断点并手动运行curl 请求以查看我试图删除的索引,我发现它仍然存在一些时间;在这些情况下,如果我继续测试,就会出现上述错误。
我尝试过断言对删除操作的响应的isAcknowledged() 方法,但它总是返回true,即使在发生错误的情况下也是如此。
我还尝试在创建操作之前进行exists() 检查。有趣的是,如果我在没有断点的情况下运行测试,exists() 检查总是返回false(即索引不存在),即使在随后会发生错误的情况下,但是如果我在创建操作之前放置了一个断点,那么exists() 检查会在发生错误的情况下返回true。
我有点不知所措。据我了解,我的请求应该是同步的,从对this question 的评论来看,这应该意味着delete() 操作只有在索引确实被删除时才会返回。
我怀疑问题的关键部分可能是这些测试是在 3 个节点的集群上运行的。在设置客户端时,我只处理其中一个节点:
client = new RestHighLevelClient(RestClient.builder(new HttpHost("example.com", 9200, "https")));
但我可以看到每个操作都被复制到其他两个节点。
当我在创建操作之前停止断点时,如果索引没有被删除,我可以看到它没有在任何节点上被删除,而且似乎不管我等待多长时间,它永远不会得到已删除。
有没有什么方法可以在创建索引之前可靠地确定索引是否已被删除?或者也许我需要在尝试删除操作之前做一些事情,以保证它会成功?
【问题讨论】:
标签: java elasticsearch automated-tests race-condition