2121
2222import org .elasticsearch .ElasticsearchException ;
2323import org .elasticsearch .ElasticsearchStatusException ;
24+ import org .elasticsearch .action .ActionListener ;
2425import org .elasticsearch .action .DocWriteRequest ;
2526import org .elasticsearch .action .DocWriteResponse ;
27+ import org .elasticsearch .action .admin .cluster .node .tasks .list .ListTasksRequest ;
28+ import org .elasticsearch .action .admin .cluster .node .tasks .list .ListTasksResponse ;
29+ import org .elasticsearch .action .admin .cluster .node .tasks .list .TaskGroup ;
2630import org .elasticsearch .action .admin .indices .get .GetIndexRequest ;
2731import org .elasticsearch .action .bulk .BulkItemResponse ;
2832import org .elasticsearch .action .bulk .BulkProcessor ;
5256import org .elasticsearch .index .query .IdsQueryBuilder ;
5357import org .elasticsearch .index .reindex .BulkByScrollResponse ;
5458import org .elasticsearch .index .reindex .DeleteByQueryRequest ;
59+ import org .elasticsearch .index .reindex .ReindexAction ;
5560import org .elasticsearch .index .reindex .ReindexRequest ;
5661import org .elasticsearch .index .reindex .UpdateByQueryRequest ;
5762import org .elasticsearch .rest .RestStatus ;
5863import org .elasticsearch .script .Script ;
5964import org .elasticsearch .script .ScriptType ;
6065import org .elasticsearch .search .fetch .subphase .FetchSourceContext ;
66+ import org .elasticsearch .tasks .RawTaskStatus ;
67+ import org .elasticsearch .tasks .TaskId ;
6168import org .joda .time .DateTime ;
6269import org .joda .time .DateTimeZone ;
6370import org .joda .time .format .DateTimeFormat ;
6471
6572import java .io .IOException ;
6673import java .util .Collections ;
6774import java .util .Map ;
75+ import java .util .concurrent .CountDownLatch ;
76+ import java .util .concurrent .TimeUnit ;
6877import java .util .concurrent .atomic .AtomicReference ;
6978
7079import static java .util .Collections .singletonMap ;
80+ import static org .hamcrest .Matchers .empty ;
81+ import static org .hamcrest .Matchers .hasSize ;
82+ import static org .hamcrest .Matchers .instanceOf ;
83+ import static org .hamcrest .Matchers .lessThan ;
7184
7285public class CrudIT extends ESRestHighLevelClientTestCase {
7386
@@ -631,7 +644,7 @@ public void testBulk() throws IOException {
631644 validateBulkResponses (nbItems , errors , bulkResponse , bulkRequest );
632645 }
633646
634- public void testReindex () throws IOException {
647+ public void testReindex () throws Exception {
635648 final String sourceIndex = "source1" ;
636649 final String destinationIndex = "dest" ;
637650 {
@@ -642,15 +655,14 @@ public void testReindex() throws IOException {
642655 .build ();
643656 createIndex (sourceIndex , settings );
644657 createIndex (destinationIndex , settings );
658+ BulkRequest bulkRequest = new BulkRequest ()
659+ .add (new IndexRequest (sourceIndex , "type" , "1" ).source (Collections .singletonMap ("foo" , "bar" ), XContentType .JSON ))
660+ .add (new IndexRequest (sourceIndex , "type" , "2" ).source (Collections .singletonMap ("foo2" , "bar2" ), XContentType .JSON ))
661+ .setRefreshPolicy (RefreshPolicy .IMMEDIATE );
645662 assertEquals (
646663 RestStatus .OK ,
647664 highLevelClient ().bulk (
648- new BulkRequest ()
649- .add (new IndexRequest (sourceIndex , "type" , "1" )
650- .source (Collections .singletonMap ("foo" , "bar" ), XContentType .JSON ))
651- .add (new IndexRequest (sourceIndex , "type" , "2" )
652- .source (Collections .singletonMap ("foo2" , "bar2" ), XContentType .JSON ))
653- .setRefreshPolicy (RefreshPolicy .IMMEDIATE ),
665+ bulkRequest ,
654666 RequestOptions .DEFAULT
655667 ).status ()
656668 );
@@ -692,6 +704,72 @@ public void testReindex() throws IOException {
692704 assertEquals (0 , bulkResponse .getBulkFailures ().size ());
693705 assertEquals (0 , bulkResponse .getSearchFailures ().size ());
694706 }
707+ {
708+ // test reindex rethrottling
709+ ReindexRequest reindexRequest = new ReindexRequest ();
710+ reindexRequest .setSourceIndices (sourceIndex );
711+ reindexRequest .setDestIndex (destinationIndex );
712+
713+ // this following settings are supposed to halt reindexing after first document
714+ reindexRequest .setSourceBatchSize (1 );
715+ reindexRequest .setRequestsPerSecond (0.00001f );
716+ final CountDownLatch reindexTaskFinished = new CountDownLatch (1 );
717+ highLevelClient ().reindexAsync (reindexRequest , RequestOptions .DEFAULT , new ActionListener <BulkByScrollResponse >() {
718+
719+ @ Override
720+ public void onResponse (BulkByScrollResponse response ) {
721+ reindexTaskFinished .countDown ();
722+ }
723+
724+ @ Override
725+ public void onFailure (Exception e ) {
726+ fail (e .toString ());
727+ }
728+ });
729+
730+ TaskGroup taskGroupToRethrottle = findTaskToRethrottle ();
731+ assertThat (taskGroupToRethrottle .getChildTasks (), empty ());
732+ TaskId taskIdToRethrottle = taskGroupToRethrottle .getTaskInfo ().getTaskId ();
733+
734+ float requestsPerSecond = 1000f ;
735+ ListTasksResponse response = execute (new RethrottleRequest (taskIdToRethrottle , requestsPerSecond ),
736+ highLevelClient ()::reindexRethrottle , highLevelClient ()::reindexRethrottleAsync );
737+ assertThat (response .getTasks (), hasSize (1 ));
738+ assertEquals (taskIdToRethrottle , response .getTasks ().get (0 ).getTaskId ());
739+ assertThat (response .getTasks ().get (0 ).getStatus (), instanceOf (RawTaskStatus .class ));
740+ assertEquals (Float .toString (requestsPerSecond ),
741+ ((RawTaskStatus ) response .getTasks ().get (0 ).getStatus ()).toMap ().get ("requests_per_second" ).toString ());
742+ reindexTaskFinished .await (2 , TimeUnit .SECONDS );
743+
744+ // any rethrottling after the reindex is done performed with the same taskId should result in a failure
745+ response = execute (new RethrottleRequest (taskIdToRethrottle , requestsPerSecond ),
746+ highLevelClient ()::reindexRethrottle , highLevelClient ()::reindexRethrottleAsync );
747+ assertTrue (response .getTasks ().isEmpty ());
748+ assertFalse (response .getNodeFailures ().isEmpty ());
749+ assertEquals (1 , response .getNodeFailures ().size ());
750+ assertEquals ("Elasticsearch exception [type=resource_not_found_exception, reason=task [" + taskIdToRethrottle + "] is missing]" ,
751+ response .getNodeFailures ().get (0 ).getCause ().getMessage ());
752+ }
753+ }
754+
755+ private TaskGroup findTaskToRethrottle () throws IOException {
756+ long start = System .nanoTime ();
757+ ListTasksRequest request = new ListTasksRequest ();
758+ request .setActions (ReindexAction .NAME );
759+ request .setDetailed (true );
760+ do {
761+ ListTasksResponse list = highLevelClient ().tasks ().list (request , RequestOptions .DEFAULT );
762+ list .rethrowFailures ("Finding tasks to rethrottle" );
763+ assertThat ("tasks are left over from the last execution of this test" ,
764+ list .getTaskGroups (), hasSize (lessThan (2 )));
765+ if (0 == list .getTaskGroups ().size ()) {
766+ // The parent task hasn't started yet
767+ continue ;
768+ }
769+ return list .getTaskGroups ().get (0 );
770+ } while (System .nanoTime () - start < TimeUnit .SECONDS .toNanos (10 ));
771+ throw new AssertionError ("Couldn't find tasks to rethrottle. Here are the running tasks " +
772+ highLevelClient ().tasks ().list (request , RequestOptions .DEFAULT ));
695773 }
696774
697775 public void testUpdateByQuery () throws IOException {
0 commit comments