1919import org .elasticsearch .action .admin .indices .mapping .put .PutMappingRequest ;
2020import org .elasticsearch .action .admin .indices .mapping .put .TransportAutoPutMappingAction ;
2121import org .elasticsearch .action .admin .indices .mapping .put .TransportPutMappingAction ;
22+ import org .elasticsearch .action .support .PlainActionFuture ;
2223import org .elasticsearch .action .support .master .AcknowledgedResponse ;
2324import org .elasticsearch .action .support .master .MasterNodeRequest ;
2425import org .elasticsearch .client .Request ;
26+ import org .elasticsearch .client .Response ;
27+ import org .elasticsearch .client .ResponseListener ;
2528import org .elasticsearch .cluster .ClusterState ;
2629import org .elasticsearch .cluster .ClusterStateUpdateTask ;
2730import org .elasticsearch .cluster .service .ClusterService ;
3538import org .elasticsearch .rest .RestUtils ;
3639import org .elasticsearch .test .ESIntegTestCase ;
3740import org .elasticsearch .test .rest .ESRestTestCase ;
41+ import org .elasticsearch .test .rest .ObjectPath ;
3842
3943import java .util .Collection ;
4044import java .util .List ;
4145import java .util .concurrent .CyclicBarrier ;
46+ import java .util .function .Consumer ;
4247
48+ import static org .elasticsearch .action .admin .indices .create .AutoCreateAction .AUTO_CREATE_INDEX_MAX_TIMEOUT_SETTING ;
4349import static org .elasticsearch .cluster .metadata .MetadataCreateIndexService .CREATE_INDEX_MAX_TIMEOUT_SETTING ;
4450import static org .elasticsearch .cluster .metadata .MetadataMappingService .PUT_MAPPING_MAX_TIMEOUT_SETTING ;
4551import static org .hamcrest .Matchers .allOf ;
@@ -53,6 +59,7 @@ public static class TestPlugin extends Plugin {
5359 public List <Setting <?>> getSettings () {
5460 return CollectionUtils .appendToCopyNoNullElements (
5561 super .getSettings (),
62+ AUTO_CREATE_INDEX_MAX_TIMEOUT_SETTING ,
5663 CREATE_INDEX_MAX_TIMEOUT_SETTING ,
5764 PUT_MAPPING_MAX_TIMEOUT_SETTING
5865 );
@@ -68,6 +75,7 @@ protected Collection<Class<? extends Plugin>> nodePlugins() {
6875 protected Settings nodeSettings (int nodeOrdinal , Settings otherSettings ) {
6976 return Settings .builder ()
7077 .put (otherSettings )
78+ .put (AUTO_CREATE_INDEX_MAX_TIMEOUT_SETTING .getKey (), "1ms" )
7179 .put (CREATE_INDEX_MAX_TIMEOUT_SETTING .getKey (), "1ms" )
7280 .put (PUT_MAPPING_MAX_TIMEOUT_SETTING .getKey (), "1ms" )
7381 .build ();
@@ -97,6 +105,67 @@ protected boolean addMockHttpTransport() {
97105 return false ; // enable HTTP
98106 }
99107
108+ public void testAutoCreateTimeoutLimit () throws Exception {
109+ final var masterClusterService = internalCluster ().getCurrentMasterNodeInstance (ClusterService .class );
110+ final var restClient = getRestClient ();
111+ final var indexName = randomIndexName ();
112+
113+ final Consumer <Request > timeoutApplier ;
114+ if (randomBoolean ()) {
115+ timeoutApplier = r -> {};
116+ } else {
117+ var timeout = randomFrom (
118+ MasterNodeRequest .INFINITE_MASTER_NODE_TIMEOUT ,
119+ TimeValue .MINUS_ONE ,
120+ TimeValue .THIRTY_SECONDS ,
121+ TimeValue .MAX_VALUE
122+ ).getStringRep ();
123+ timeoutApplier = r -> r .addParameter ("timeout" , timeout );
124+ }
125+
126+ try (var ignored = withBlockedMasterService (masterClusterService )) {
127+ final var request = new Request ("PUT" , "/" + indexName + "/_bulk" );
128+ request .setJsonEntity ("""
129+ {"index":{}}
130+ {}
131+ """ );
132+ timeoutApplier .accept (request );
133+ final var response = ObjectPath .createFromResponse (restClient .performRequest (request ));
134+ logger .info ("--> response={}" , response );
135+ assertTrue (response .evaluate ("errors" ));
136+ assertEquals (RestStatus .TOO_MANY_REQUESTS .getStatus (), (int ) response .evaluate ("items.0.index.status" ));
137+ assertThat (response .evaluate ("items.0.index.error.type" ), equalTo ("process_cluster_event_timeout_exception" ));
138+ assertThat (response .evaluate ("items.0.index.error.reason" ), containsString ("failed to process cluster event" ));
139+ }
140+
141+ updateClusterSettings (Settings .builder ().put (AUTO_CREATE_INDEX_MAX_TIMEOUT_SETTING .getKey (), randomFrom ("-1" , "60s" , "1h" )));
142+
143+ final PlainActionFuture <Response > bulkResponseFuture = new PlainActionFuture <>();
144+ try (var ignored = withBlockedMasterService (masterClusterService )) {
145+ final var request = new Request ("PUT" , "/" + indexName + "/_bulk" );
146+ request .setJsonEntity ("""
147+ {"index":{}}
148+ {}
149+ """ );
150+ timeoutApplier .accept (request );
151+ restClient .performRequestAsync (request , new ResponseListener () {
152+ @ Override
153+ public void onSuccess (Response response ) {
154+ bulkResponseFuture .onResponse (response );
155+ }
156+
157+ @ Override
158+ public void onFailure (Exception exception ) {
159+ bulkResponseFuture .onFailure (exception );
160+ }
161+ });
162+ awaitPendingTask (masterClusterService , "auto create [" + indexName + "]" );
163+ }
164+ safeGet (bulkResponseFuture );
165+
166+ updateClusterSettings (Settings .builder ().putNull (AUTO_CREATE_INDEX_MAX_TIMEOUT_SETTING .getKey ()));
167+ }
168+
100169 public void testReducePriorities () throws Exception {
101170 final var masterClusterService = internalCluster ().getCurrentMasterNodeInstance (ClusterService .class );
102171 final var restClient = getRestClient ();
0 commit comments