mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-08 13:12:10 +00:00
Extend BulkFailureException.failedDocuments return type to show more details about failure.
Original Pull Request #2633 Related tickets #2619
This commit is contained in:
parent
341518d0cc
commit
c7000fc004
@ -6,6 +6,14 @@ This section describes breaking changes from version 5.1.x to 5.2.x and how remo
|
|||||||
[[elasticsearch-migration-guide-5.1-5.2.breaking-changes]]
|
[[elasticsearch-migration-guide-5.1-5.2.breaking-changes]]
|
||||||
== Breaking Changes
|
== Breaking Changes
|
||||||
|
|
||||||
|
In the `org.springframework.data.elasticsearch.BulkFailureException` class, the return type of the `getFailedDocuments` is changed from `Map<String, String>`
|
||||||
|
to `Map<String, FailureDetails>`, which allows to get additional details about failure reasons.
|
||||||
|
|
||||||
|
The definition of the `FailureDetails` class (inner to `BulkFailureException`):
|
||||||
|
[source,java]
|
||||||
|
public record FailureDetails(Integer status, String errorMessage) {
|
||||||
|
}
|
||||||
|
|
||||||
[[elasticsearch-migration-guide-5.1-5.2.deprecations]]
|
[[elasticsearch-migration-guide-5.1-5.2.deprecations]]
|
||||||
== Deprecations
|
== Deprecations
|
||||||
|
|
||||||
|
@ -21,17 +21,27 @@ import java.util.Map;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Peter-Josef Meisch
|
* @author Peter-Josef Meisch
|
||||||
|
* @author Illia Ulianov
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
*/
|
*/
|
||||||
public class BulkFailureException extends DataRetrievalFailureException {
|
public class BulkFailureException extends DataRetrievalFailureException {
|
||||||
private final Map<String, String> failedDocuments;
|
private final Map<String, FailureDetails> failedDocuments;
|
||||||
|
|
||||||
public BulkFailureException(String msg, Map<String, String> failedDocuments) {
|
public BulkFailureException(String msg, Map<String, FailureDetails> failedDocuments) {
|
||||||
super(msg);
|
super(msg);
|
||||||
this.failedDocuments = failedDocuments;
|
this.failedDocuments = failedDocuments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getFailedDocuments() {
|
public Map<String, FailureDetails> getFailedDocuments() {
|
||||||
return failedDocuments;
|
return failedDocuments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Details about a document saving failure.
|
||||||
|
*
|
||||||
|
* @author Illia Ulianov
|
||||||
|
* @since 5.2
|
||||||
|
*/
|
||||||
|
public record FailureDetails(Integer status, String errorMessage) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Peter-Josef Meisch
|
* @author Peter-Josef Meisch
|
||||||
* @author Hamid Rahimi
|
* @author Hamid Rahimi
|
||||||
|
* @author Illia Ulianov
|
||||||
* @since 4.4
|
* @since 4.4
|
||||||
*/
|
*/
|
||||||
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
||||||
@ -637,11 +638,11 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
|
|||||||
protected List<IndexedObjectInformation> checkForBulkOperationFailure(BulkResponse bulkResponse) {
|
protected List<IndexedObjectInformation> checkForBulkOperationFailure(BulkResponse bulkResponse) {
|
||||||
|
|
||||||
if (bulkResponse.errors()) {
|
if (bulkResponse.errors()) {
|
||||||
Map<String, String> failedDocuments = new HashMap<>();
|
Map<String, BulkFailureException.FailureDetails> failedDocuments = new HashMap<>();
|
||||||
for (BulkResponseItem item : bulkResponse.items()) {
|
for (BulkResponseItem item : bulkResponse.items()) {
|
||||||
|
|
||||||
if (item.error() != null) {
|
if (item.error() != null) {
|
||||||
failedDocuments.put(item.id(), item.error().reason());
|
failedDocuments.put(item.id(), new BulkFailureException.FailureDetails(item.status(), item.error().reason()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new BulkFailureException(
|
throw new BulkFailureException(
|
||||||
|
@ -68,6 +68,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* Elasticsearch client.
|
* Elasticsearch client.
|
||||||
*
|
*
|
||||||
* @author Peter-Josef Meisch
|
* @author Peter-Josef Meisch
|
||||||
|
* @author Illia Ulianov
|
||||||
* @since 4.4
|
* @since 4.4
|
||||||
*/
|
*/
|
||||||
public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearchTemplate {
|
public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearchTemplate {
|
||||||
@ -250,12 +251,12 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
|
|||||||
private Mono<BulkResponse> checkForBulkOperationFailure(BulkResponse bulkResponse) {
|
private Mono<BulkResponse> checkForBulkOperationFailure(BulkResponse bulkResponse) {
|
||||||
|
|
||||||
if (bulkResponse.errors()) {
|
if (bulkResponse.errors()) {
|
||||||
Map<String, String> failedDocuments = new HashMap<>();
|
Map<String, BulkFailureException.FailureDetails> failedDocuments = new HashMap<>();
|
||||||
|
|
||||||
for (BulkResponseItem item : bulkResponse.items()) {
|
for (BulkResponseItem item : bulkResponse.items()) {
|
||||||
|
|
||||||
if (item.error() != null) {
|
if (item.error() != null) {
|
||||||
failedDocuments.put(item.id(), item.error().reason());
|
failedDocuments.put(item.id(), new BulkFailureException.FailureDetails(item.status(), item.error().reason()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BulkFailureException exception = new BulkFailureException(
|
BulkFailureException exception = new BulkFailureException(
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Illia Ulianov
|
||||||
|
*/
|
||||||
|
class BulkFailureExceptionTest {
|
||||||
|
|
||||||
|
@Test // #2619
|
||||||
|
void shouldCreateBulkException() {
|
||||||
|
String documentId = "id1";
|
||||||
|
var failureDetails = new BulkFailureException.FailureDetails(409, "conflict");
|
||||||
|
var exception = new BulkFailureException("Test message", Map.of(documentId, failureDetails));
|
||||||
|
assertThat(exception.getFailedDocuments()).containsEntry(documentId, failureDetails);
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,7 @@ import java.util.*;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||||
import org.assertj.core.api.SoftAssertions;
|
import org.assertj.core.api.SoftAssertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
@ -48,6 +49,7 @@ import org.springframework.data.annotation.Version;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.elasticsearch.BulkFailureException;
|
||||||
import org.springframework.data.elasticsearch.annotations.*;
|
import org.springframework.data.elasticsearch.annotations.*;
|
||||||
import org.springframework.data.elasticsearch.annotations.Field;
|
import org.springframework.data.elasticsearch.annotations.Field;
|
||||||
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
||||||
@ -98,6 +100,7 @@ import org.springframework.lang.Nullable;
|
|||||||
* @author Haibo Liu
|
* @author Haibo Liu
|
||||||
* @author scoobyzhang
|
* @author scoobyzhang
|
||||||
* @author Hamid Rahimi
|
* @author Hamid Rahimi
|
||||||
|
* @author Illia Ulianov
|
||||||
*/
|
*/
|
||||||
@SpringIntegrationTest
|
@SpringIntegrationTest
|
||||||
public abstract class ElasticsearchIntegrationTests {
|
public abstract class ElasticsearchIntegrationTests {
|
||||||
@ -3616,6 +3619,27 @@ public abstract class ElasticsearchIntegrationTests {
|
|||||||
operations.search(query, SampleEntity.class);
|
operations.search(query, SampleEntity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // #2619
|
||||||
|
void shouldFailWithConflictOnAttemptToSaveWithSameVersion() {
|
||||||
|
var entity1 = new VersionedEntity();
|
||||||
|
entity1.setId("id1");
|
||||||
|
entity1.setVersion(1L);
|
||||||
|
var entity2 = new VersionedEntity();
|
||||||
|
entity2.setId("id2");
|
||||||
|
entity2.setVersion(1L);
|
||||||
|
operations.save(entity1, entity2);
|
||||||
|
|
||||||
|
entity1.setVersion(2L);
|
||||||
|
assertThatThrownBy(() -> operations.save(entity1, entity2))
|
||||||
|
.asInstanceOf(InstanceOfAssertFactories.type(BulkFailureException.class))
|
||||||
|
.extracting(BulkFailureException::getFailedDocuments)
|
||||||
|
.asInstanceOf(InstanceOfAssertFactories.map(String.class, BulkFailureException.FailureDetails.class))
|
||||||
|
.containsOnlyKeys("id2")
|
||||||
|
.extracting(Map::values)
|
||||||
|
.asInstanceOf(InstanceOfAssertFactories.collection(BulkFailureException.FailureDetails.class))
|
||||||
|
.allMatch(failureStatus -> failureStatus.status().equals(409));
|
||||||
|
}
|
||||||
|
|
||||||
// region entities
|
// region entities
|
||||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||||
@Setting(shards = 1, replicas = 0, refreshInterval = "-1")
|
@Setting(shards = 1, replicas = 0, refreshInterval = "-1")
|
||||||
|
@ -20,6 +20,8 @@ import static org.assertj.core.api.Assertions.*;
|
|||||||
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
|
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
|
||||||
import static org.springframework.data.elasticsearch.core.query.StringQuery.MATCH_ALL;
|
import static org.springframework.data.elasticsearch.core.query.StringQuery.MATCH_ALL;
|
||||||
|
|
||||||
|
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||||
|
import org.springframework.data.elasticsearch.BulkFailureException;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
@ -89,6 +91,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* @author Roman Puchkovskiy
|
* @author Roman Puchkovskiy
|
||||||
* @author George Popides
|
* @author George Popides
|
||||||
* @author Sijia Liu
|
* @author Sijia Liu
|
||||||
|
* @author Illia Ulianov
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("SpringJavaAutowiredMembersInspection")
|
@SuppressWarnings("SpringJavaAutowiredMembersInspection")
|
||||||
@SpringIntegrationTest
|
@SpringIntegrationTest
|
||||||
@ -1192,6 +1195,27 @@ public abstract class ReactiveElasticsearchIntegrationTests {
|
|||||||
}) //
|
}) //
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // #2619
|
||||||
|
void shouldFailWithConflictOnAttemptToSaveWithSameVersion() {
|
||||||
|
var entity1 = new VersionedEntity();
|
||||||
|
entity1.setId("id1");
|
||||||
|
entity1.setVersion(1L);
|
||||||
|
var entity2 = new VersionedEntity();
|
||||||
|
entity2.setId("id2");
|
||||||
|
entity2.setVersion(1L);
|
||||||
|
operations.saveAll(Arrays.asList(entity1, entity2), VersionedEntity.class).blockLast();
|
||||||
|
|
||||||
|
entity1.setVersion(2L);
|
||||||
|
assertThatThrownBy(() -> operations.saveAll(Arrays.asList(entity1, entity2), VersionedEntity.class).blockLast())
|
||||||
|
.asInstanceOf(InstanceOfAssertFactories.type(BulkFailureException.class))
|
||||||
|
.extracting(BulkFailureException::getFailedDocuments)
|
||||||
|
.asInstanceOf(InstanceOfAssertFactories.map(String.class, BulkFailureException.FailureDetails.class))
|
||||||
|
.containsOnlyKeys("id2").extracting(Map::values)
|
||||||
|
.asInstanceOf(InstanceOfAssertFactories.collection(BulkFailureException.FailureDetails.class))
|
||||||
|
.allMatch(failureStatus -> failureStatus.status().equals(409));
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Helper functions
|
// region Helper functions
|
||||||
|
Loading…
x
Reference in New Issue
Block a user