@@ -144,7 +144,8 @@ public BulkRetryStrategy createObjectUnderTest(
144144 bulkRequestSupplier ,
145145 PIPELINE_NAME ,
146146 PLUGIN_NAME ,
147- null );
147+ null ,
148+ false );
148149 }
149150
150151 public BulkRetryStrategy createObjectUnderTest (
@@ -171,7 +172,8 @@ public BulkRetryStrategy createObjectUnderTest(
171172 bulkRequestSupplier ,
172173 PIPELINE_NAME ,
173174 PLUGIN_NAME ,
174- null );
175+ null ,
176+ false );
175177 }
176178
177179 public BulkRetryStrategy createObjectUnderTest (
@@ -199,7 +201,35 @@ public BulkRetryStrategy createObjectUnderTest(
199201 bulkRequestSupplier ,
200202 PIPELINE_NAME ,
201203 PLUGIN_NAME ,
202- existingDocumentQueryManager );
204+ existingDocumentQueryManager ,
205+ false );
206+ }
207+
208+ public BulkRetryStrategy createObjectUnderTestWithExternalVersioning (
209+ final RequestFunction <AccumulatingBulkRequest <BulkOperationWrapper , BulkRequest >, BulkResponse > requestFunction ,
210+ final BiConsumer <List <FailedBulkOperation >, Throwable > logFailure ,
211+ final Supplier <AccumulatingBulkRequest > bulkRequestSupplier
212+ ) {
213+ return new BulkRetryStrategy (
214+ requestFunction ,
215+ logFailure ,
216+ (operations ) -> {
217+ for (BulkOperationWrapper operation : operations ) {
218+ if (operation .getEvent () != null ) {
219+ operation .getEvent ().getEventHandle ().release (true );
220+ }
221+ if (operation .getEventHandle () != null ) {
222+ operation .getEventHandle ().release (true );
223+ }
224+ }
225+ },
226+ pluginMetrics ,
227+ Integer .MAX_VALUE ,
228+ bulkRequestSupplier ,
229+ PIPELINE_NAME ,
230+ PLUGIN_NAME ,
231+ null ,
232+ true );
203233 }
204234
205235 @ Test
@@ -629,12 +659,6 @@ public void testExecuteWithMaxRetriesAndSuccesses() throws Exception {
629659 assertThat (maxRetriesLimitReached , equalTo (true ));
630660 assertEquals (numEventsSucceeded , 2 );
631661 assertEquals (numEventsFailed , 2 );
632-
633- final List <Measurement > documentVersionConflictMeasurement = MetricsTestUtil .getMeasurementList (
634- new StringJoiner (MetricNames .DELIMITER ).add (PIPELINE_NAME ).add (PLUGIN_NAME )
635- .add (BulkRetryStrategy .DOCUMENTS_VERSION_CONFLICT_ERRORS ).toString ());
636- assertEquals (1 , documentVersionConflictMeasurement .size ());
637- assertEquals (1.0 , documentVersionConflictMeasurement .get (0 ).getValue (), 0 );
638662 }
639663
640664 @ Test
@@ -694,6 +718,128 @@ public void testExecuteNonRetryableResponse() throws Exception {
694718 assertEquals (3.0 , documentErrorsMeasurements .get (0 ).getValue (), 0 );
695719 }
696720
721+ @ Test
722+ public void testExecute_VersionConflictDoesNotIncrementDocumentErrors () throws Exception {
723+ final String testIndex = "version-conflict-index" ;
724+ final RequestFunction <AccumulatingBulkRequest <BulkOperationWrapper , BulkRequest >, BulkResponse > requestFunction = mock (RequestFunction .class );
725+ final Supplier <AccumulatingBulkRequest > bulkRequestSupplier = () -> new JavaClientAccumulatingUncompressedBulkRequest (new BulkRequest .Builder ());
726+
727+ final BulkRetryStrategy bulkRetryStrategy = createObjectUnderTestWithExternalVersioning (
728+ requestFunction , logFailureConsumer , bulkRequestSupplier );
729+
730+ final IndexOperation <SerializedJson > indexOp1 = new IndexOperation .Builder <SerializedJson >().index (testIndex ).id ("1" ).document (arbitraryDocument ()).build ();
731+ final IndexOperation <SerializedJson > indexOp2 = new IndexOperation .Builder <SerializedJson >().index (testIndex ).id ("2" ).document (arbitraryDocument ()).build ();
732+ final IndexOperation <SerializedJson > indexOp3 = new IndexOperation .Builder <SerializedJson >().index (testIndex ).id ("3" ).document (arbitraryDocument ()).build ();
733+
734+ final BulkOperationWrapper wrapper1 = new BulkOperationWrapper (new BulkOperation .Builder ().index (indexOp1 ).build (), eventHandle1 );
735+ final BulkOperationWrapper wrapper2 = new BulkOperationWrapper (new BulkOperation .Builder ().index (indexOp2 ).build (), eventHandle2 );
736+ final BulkOperationWrapper wrapper3 = new BulkOperationWrapper (new BulkOperation .Builder ().index (indexOp3 ).build (), eventHandle3 );
737+
738+ final AccumulatingBulkRequest accumulatingBulkRequest = new JavaClientAccumulatingUncompressedBulkRequest (new BulkRequest .Builder ());
739+ accumulatingBulkRequest .addOperation (wrapper1 );
740+ accumulatingBulkRequest .addOperation (wrapper2 );
741+ accumulatingBulkRequest .addOperation (wrapper3 );
742+
743+ // Response: 1 success, 1 version conflict, 1 bad request
744+ final BulkResponseItem successItem = successItemResponse (testIndex );
745+ final BulkResponseItem versionConflictItem = versionConflictErrorItemResponse ();
746+ final BulkResponseItem badRequestItem = badRequestItemResponse (testIndex );
747+ final List <BulkResponseItem > responseItems = Arrays .asList (successItem , versionConflictItem , badRequestItem );
748+
749+ final BulkResponse bulkResponse = mock (BulkResponse .class );
750+ when (bulkResponse .errors ()).thenReturn (true );
751+ when (bulkResponse .items ()).thenReturn (responseItems );
752+ when (requestFunction .apply (any ())).thenReturn (bulkResponse );
753+
754+ numEventsSucceeded = 0 ;
755+ numEventsFailed = 0 ;
756+ bulkRetryStrategy .execute (accumulatingBulkRequest );
757+
758+ // Version conflict should NOT be counted as a document error
759+ final List <Measurement > documentErrorsMeasurements = MetricsTestUtil .getMeasurementList (
760+ new StringJoiner (MetricNames .DELIMITER ).add (PIPELINE_NAME ).add (PLUGIN_NAME )
761+ .add (BulkRetryStrategy .DOCUMENT_ERRORS ).toString ());
762+ assertEquals (1 , documentErrorsMeasurements .size ());
763+ assertEquals (1.0 , documentErrorsMeasurements .get (0 ).getValue (), 0 );
764+
765+ // Version conflict should be counted in its own metric
766+ final List <Measurement > versionConflictMeasurements = MetricsTestUtil .getMeasurementList (
767+ new StringJoiner (MetricNames .DELIMITER ).add (PIPELINE_NAME ).add (PLUGIN_NAME )
768+ .add (BulkRetryStrategy .DOCUMENTS_VERSION_CONFLICT_ERRORS ).toString ());
769+ assertEquals (1 , versionConflictMeasurements .size ());
770+ assertEquals (1.0 , versionConflictMeasurements .get (0 ).getValue (), 0 );
771+
772+ // Success metric should count the 1 successful document
773+ final List <Measurement > successMeasurements = MetricsTestUtil .getMeasurementList (
774+ new StringJoiner (MetricNames .DELIMITER ).add (PIPELINE_NAME ).add (PLUGIN_NAME )
775+ .add (BulkRetryStrategy .DOCUMENTS_SUCCESS ).toString ());
776+ assertEquals (1 , successMeasurements .size ());
777+ assertEquals (1.0 , successMeasurements .get (0 ).getValue (), 0 );
778+
779+ // Version conflict event handle should be released with true (success)
780+ verify (eventHandle2 ).release (true );
781+ }
782+
783+ @ Test
784+ public void testExecute_VersionConflictIncrementsDocumentErrors_WhenNotExternalVersioning () throws Exception {
785+ final String testIndex = "version-conflict-index" ;
786+ final RequestFunction <AccumulatingBulkRequest <BulkOperationWrapper , BulkRequest >, BulkResponse > requestFunction = mock (RequestFunction .class );
787+ final Supplier <AccumulatingBulkRequest > bulkRequestSupplier = () -> new JavaClientAccumulatingUncompressedBulkRequest (new BulkRequest .Builder ());
788+
789+ // Use default (non-external versioning)
790+ final BulkRetryStrategy bulkRetryStrategy = createObjectUnderTest (
791+ requestFunction , logFailureConsumer , bulkRequestSupplier );
792+
793+ final IndexOperation <SerializedJson > indexOp1 = new IndexOperation .Builder <SerializedJson >().index (testIndex ).id ("1" ).document (arbitraryDocument ()).build ();
794+ final IndexOperation <SerializedJson > indexOp2 = new IndexOperation .Builder <SerializedJson >().index (testIndex ).id ("2" ).document (arbitraryDocument ()).build ();
795+ final IndexOperation <SerializedJson > indexOp3 = new IndexOperation .Builder <SerializedJson >().index (testIndex ).id ("3" ).document (arbitraryDocument ()).build ();
796+
797+ final BulkOperationWrapper wrapper1 = new BulkOperationWrapper (new BulkOperation .Builder ().index (indexOp1 ).build (), eventHandle1 );
798+ final BulkOperationWrapper wrapper2 = new BulkOperationWrapper (new BulkOperation .Builder ().index (indexOp2 ).build (), eventHandle2 );
799+ final BulkOperationWrapper wrapper3 = new BulkOperationWrapper (new BulkOperation .Builder ().index (indexOp3 ).build (), eventHandle3 );
800+
801+ final AccumulatingBulkRequest accumulatingBulkRequest = new JavaClientAccumulatingUncompressedBulkRequest (new BulkRequest .Builder ());
802+ accumulatingBulkRequest .addOperation (wrapper1 );
803+ accumulatingBulkRequest .addOperation (wrapper2 );
804+ accumulatingBulkRequest .addOperation (wrapper3 );
805+
806+ // Response: 1 success, 1 version conflict, 1 bad request
807+ final BulkResponseItem successItem = successItemResponse (testIndex );
808+ final BulkResponseItem versionConflictItem = versionConflictErrorItemResponse ();
809+ final BulkResponseItem badRequestItem = badRequestItemResponse (testIndex );
810+ final List <BulkResponseItem > responseItems = Arrays .asList (successItem , versionConflictItem , badRequestItem );
811+
812+ final BulkResponse bulkResponse = mock (BulkResponse .class );
813+ when (bulkResponse .errors ()).thenReturn (true );
814+ when (bulkResponse .items ()).thenReturn (responseItems );
815+ when (requestFunction .apply (any ())).thenReturn (bulkResponse );
816+
817+ numEventsSucceeded = 0 ;
818+ numEventsFailed = 0 ;
819+ bulkRetryStrategy .execute (accumulatingBulkRequest );
820+
821+ // Without external versioning, version conflict SHOULD be counted as a document error
822+ final List <Measurement > documentErrorsMeasurements = MetricsTestUtil .getMeasurementList (
823+ new StringJoiner (MetricNames .DELIMITER ).add (PIPELINE_NAME ).add (PLUGIN_NAME )
824+ .add (BulkRetryStrategy .DOCUMENT_ERRORS ).toString ());
825+ assertEquals (1 , documentErrorsMeasurements .size ());
826+ assertEquals (2.0 , documentErrorsMeasurements .get (0 ).getValue (), 0 );
827+
828+ // Version conflict metric should NOT be incremented without external versioning
829+ final List <Measurement > versionConflictMeasurements = MetricsTestUtil .getMeasurementList (
830+ new StringJoiner (MetricNames .DELIMITER ).add (PIPELINE_NAME ).add (PLUGIN_NAME )
831+ .add (BulkRetryStrategy .DOCUMENTS_VERSION_CONFLICT_ERRORS ).toString ());
832+ assertEquals (1 , versionConflictMeasurements .size ());
833+ assertEquals (0.0 , versionConflictMeasurements .get (0 ).getValue (), 0 );
834+
835+ // Success metric should count the 1 successful document
836+ final List <Measurement > successMeasurements = MetricsTestUtil .getMeasurementList (
837+ new StringJoiner (MetricNames .DELIMITER ).add (PIPELINE_NAME ).add (PLUGIN_NAME )
838+ .add (BulkRetryStrategy .DOCUMENTS_SUCCESS ).toString ());
839+ assertEquals (1 , successMeasurements .size ());
840+ assertEquals (1.0 , successMeasurements .get (0 ).getValue (), 0 );
841+ }
842+
697843 @ Test
698844 public void testExecute_DeleteNotFound_RetriesAndSucceeds () throws Exception {
699845 final String testIndex = "delete-index" ;
0 commit comments