This is an automated email from the ASF dual-hosted git repository.

cgivre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git


The following commit(s) were added to refs/heads/master by this push:
     new 77696c0796 DRILL-8342: Add Automatic Retry for Rate Limited APIs 
(#2691)
77696c0796 is described below

commit 77696c079661280497730da082e479c187709049
Author: Charles S. Givre <[email protected]>
AuthorDate: Mon Oct 24 11:50:14 2022 -0400

    DRILL-8342: Add Automatic Retry for Rate Limited APIs (#2691)
---
 contrib/storage-http/Pagination.md                 | 20 +++++----
 .../exec/store/http/HttpStoragePluginConfig.java   | 19 ++++++++-
 .../drill/exec/store/http/util/SimpleHttp.java     | 49 ++++++++++++++++++++--
 .../drill/exec/store/http/TestHttpPlugin.java      |  5 ++-
 .../exec/store/http/TestHttpUDFFunctions.java      |  2 +-
 .../exec/store/http/TestHttpUDFWithAliases.java    |  2 +-
 .../drill/exec/store/http/TestOAuthProcess.java    |  2 +-
 .../exec/store/http/TestOAuthTokenUpdate.java      |  2 +-
 .../drill/exec/store/http/TestPagination.java      | 31 +++++++++++++-
 .../drill/exec/store/http/TestProvidedSchema.java  |  2 +-
 .../http/TestUserTranslationInHttpPlugin.java      |  4 +-
 11 files changed, 114 insertions(+), 24 deletions(-)

diff --git a/contrib/storage-http/Pagination.md 
b/contrib/storage-http/Pagination.md
index 8855fb236f..f555060f03 100644
--- a/contrib/storage-http/Pagination.md
+++ b/contrib/storage-http/Pagination.md
@@ -1,12 +1,18 @@
 # Auto Pagination in Drill
-Remote APIs frequently implement some sort of pagination as a way of limiting 
results.  However, if you are performing bulk data analysis, it is necessary to 
reassemble the 
+Remote APIs frequently implement some sort of pagination as a way of limiting 
results.  However, if you are performing bulk data analysis, it is necessary to 
reassemble the
 data into one larger dataset.  Drill's auto-pagination features allow this to 
happen in the background, so that the user will get clean data back.
 
-To use a paginator, you simply have to configure the paginator in the 
connection for the particular API.  
+To use a paginator, you simply have to configure the paginator in the 
connection for the particular API.
 
 ## Words of Caution
 While extremely powerful, the auto-pagination feature has the potential to run 
afoul of APIs rate limits and even potentially DDoS an API. Please use with 
extreme care.
 
+## Rate Limits
+When using automatic pagination, you may encounter APIs that have burst limits 
or other limits
+as to the maximum number of requests in a minute or other amount of time.  
Drill allows you to
+set a `retryDelay` parameter which is the number of milliseconds that Drill 
should wait before
+resending the request.  This defaults to 1 second.  This option is set in the 
configuration for
+the HTTP plugin.
 
 ## Offset Pagination
 Offset Pagination uses commands similar to SQL which has a `LIMIT` and an 
`OFFSET`.  With an offset paginator, let's say you want 200 records and the  
page size is 50 records, the offset paginator will break up your query into 4 
requests as shown below:
@@ -17,7 +23,7 @@ Offset Pagination uses commands similar to SQL which has a 
`LIMIT` and an `OFFSE
 * myapi.com?limit=50&offset=150
 
 ### Configuring Offset Pagination
-To configure an offset paginator, simply add the following to the 
configuration for your connection. 
+To configure an offset paginator, simply add the following to the 
configuration for your connection.
 
 ```json
 "paginator": {
@@ -29,7 +35,7 @@ To configure an offset paginator, simply add the following to 
the configuration
 ```
 
 ## Page Pagination
-Page pagination is very similar to offset pagination except instead of using 
an `OFFSET` it uses a page number. 
+Page pagination is very similar to offset pagination except instead of using 
an `OFFSET` it uses a page number.
 
 ```json
  "paginator": {
@@ -42,9 +48,9 @@ Page pagination is very similar to offset pagination except 
instead of using an
 In either case, the `pageSize` parameter should be set to the maximum page 
size allowable by the API.  This will minimize the number of requests Drill is 
making.
 
 ## Index / KeySet Pagination
-Index or KeySet pagination is when the API itself returns values to generate 
the next page. 
+Index or KeySet pagination is when the API itself returns values to generate 
the next page.
 
-Consider an API that returned data like this: 
+Consider an API that returned data like this:
 
 ```json
 {
@@ -69,4 +75,4 @@ There are three possible parameters:
 * `nextPageParam`: The parameter name which returns a complete URL of the next 
page.
 
 
-** Note: Index / Keyset Pagination is only implemented for APIs that return 
JSON ** 
+** Note: Index / Keyset Pagination is only implemented for APIs that return 
JSON **
diff --git 
a/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/HttpStoragePluginConfig.java
 
b/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/HttpStoragePluginConfig.java
index c19b5b2821..5c38430af6 100644
--- 
a/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/HttpStoragePluginConfig.java
+++ 
b/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/HttpStoragePluginConfig.java
@@ -17,6 +17,7 @@
  */
 package org.apache.drill.exec.store.http;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import org.apache.drill.common.PlanStringBuilder;
 import org.apache.drill.common.exceptions.UserException;
 import org.apache.drill.common.logical.OAuthConfig;
@@ -42,8 +43,10 @@ import java.util.concurrent.TimeUnit;
 
 
 @JsonTypeName(HttpStoragePluginConfig.NAME)
+@JsonInclude(JsonInclude.Include.NON_DEFAULT)
 public class HttpStoragePluginConfig extends StoragePluginConfig {
   private static final Logger logger = 
LoggerFactory.getLogger(HttpStoragePluginConfig.class);
+  private static final int DEFAULT_RATE_LIMIT = 1000;
   public static final String NAME = "http";
 
   public final Map<String, HttpApiConfig> connections;
@@ -55,11 +58,13 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
    * Timeout in {@link TimeUnit#SECONDS}.
    */
   public final int timeout;
+  public final int retryDelay;
 
   @JsonCreator
   public HttpStoragePluginConfig(@JsonProperty("cacheResults") Boolean 
cacheResults,
                                  @JsonProperty("connections") Map<String, 
HttpApiConfig> connections,
                                  @JsonProperty("timeout") Integer timeout,
+                                 @JsonProperty("retryDelay") Integer 
retryDelay,
                                  @JsonProperty("username") String username,
                                  @JsonProperty("password") String password,
                                  @JsonProperty("proxyHost") String proxyHost,
@@ -84,6 +89,7 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
         AuthMode.parseOrDefault(authMode, AuthMode.SHARED_USER),
       oAuthConfig);
     this.cacheResults = cacheResults != null && cacheResults;
+    this.retryDelay = (retryDelay == null || retryDelay < 0) ? 
DEFAULT_RATE_LIMIT : retryDelay;
 
     this.connections = CaseInsensitiveMap.newHashMap();
     if (connections != null) {
@@ -121,6 +127,7 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
     this.proxyPort = that.proxyPort;
     this.proxyType = that.proxyType;
     this.oAuthConfig = that.oAuthConfig;
+    this.retryDelay = that.retryDelay;
   }
 
   /**
@@ -139,6 +146,7 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
     this.proxyPort = that.proxyPort;
     this.proxyType = that.proxyType;
     this.oAuthConfig = that.oAuthConfig;
+    this.retryDelay = that.retryDelay;
   }
 
   private static String normalize(String value) {
@@ -158,7 +166,7 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
     return new HttpStoragePluginConfig(
       cacheResults,
       configFor(connectionName),
-      timeout,
+      timeout, retryDelay,
       username(),
       password(),
       proxyHost,
@@ -189,6 +197,7 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
     return Objects.equals(connections, thatConfig.connections) &&
       Objects.equals(cacheResults, thatConfig.cacheResults) &&
       Objects.equals(proxyHost, thatConfig.proxyHost) &&
+      Objects.equals(retryDelay, thatConfig.retryDelay) &&
       Objects.equals(proxyPort, thatConfig.proxyPort) &&
       Objects.equals(proxyType, thatConfig.proxyType) &&
       Objects.equals(oAuthConfig, thatConfig.oAuthConfig) &&
@@ -202,6 +211,7 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
       .field("connections", connections)
       .field("cacheResults", cacheResults)
       .field("timeout", timeout)
+      .field("retryDelay", retryDelay)
       .field("proxyHost", proxyHost)
       .field("proxyPort", proxyPort)
       .field("credentialsProvider", credentialsProvider)
@@ -213,7 +223,7 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
 
   @Override
   public int hashCode() {
-    return Objects.hash(connections, cacheResults, timeout,
+    return Objects.hash(connections, cacheResults, timeout, retryDelay,
         proxyHost, proxyPort, proxyType, oAuthConfig, credentialsProvider, 
authMode);
   }
 
@@ -226,6 +236,11 @@ public class HttpStoragePluginConfig extends 
StoragePluginConfig {
   @JsonProperty("timeout")
   public int timeout() { return timeout;}
 
+  @JsonProperty("retryDelay")
+  public int retryDelay() {
+    return retryDelay;
+  }
+
    @JsonProperty("proxyHost")
   public String proxyHost() { return proxyHost; }
 
diff --git 
a/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/util/SimpleHttp.java
 
b/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/util/SimpleHttp.java
index e751f61cb5..d0f12f26c2 100644
--- 
a/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/util/SimpleHttp.java
+++ 
b/contrib/storage-http/src/main/java/org/apache/drill/exec/store/http/util/SimpleHttp.java
@@ -123,6 +123,7 @@ public class SimpleHttp implements AutoCloseable {
   private final HttpStoragePluginConfig pluginConfig;
   private final HttpApiConfig apiConfig;
   private final OAuthConfig oAuthConfig;
+  private final int rateLimit;
   private String responseMessage;
   private int responseCode;
   private String responseProtocol;
@@ -140,6 +141,7 @@ public class SimpleHttp implements AutoCloseable {
     this.filters = scanDefn.filters();
     this.url = url;
     this.tempDir = tempDir;
+    this.rateLimit = scanDefn.tableSpec().config().retryDelay();
     this.proxyConfig = proxyConfig;
     this.errorContext = errorContext;
     this.tokenTable = scanDefn.tableSpec().getTokenTable();
@@ -162,7 +164,7 @@ public class SimpleHttp implements AutoCloseable {
    */
   public SimpleHttp(HttpUrl url, File tempDir, HttpProxyConfig proxyConfig, 
CustomErrorContext errorContext,
                     Paginator paginator, PersistentTokenTable tokenTable, 
HttpStoragePluginConfig pluginConfig,
-                    HttpApiConfig endpointConfig, String connection, 
Map<String, String> filters) {
+                    HttpApiConfig endpointConfig, String connection, 
Map<String, String> filters, int rateLimit) {
     this.url = url;
     this.tempDir = tempDir;
     this.proxyConfig = proxyConfig;
@@ -185,6 +187,7 @@ public class SimpleHttp implements AutoCloseable {
     this.apiConfig = endpointConfig;
     this.connection = connection;
     this.filters = filters;
+    this.rateLimit = rateLimit;
     this.oAuthConfig = pluginConfig.oAuthConfig();
     this.client = setupHttpClient();
   }
@@ -240,13 +243,13 @@ public class SimpleHttp implements AutoCloseable {
     builder.connectTimeout(timeout, TimeUnit.SECONDS);
     builder.writeTimeout(timeout, TimeUnit.SECONDS);
     builder.readTimeout(timeout, TimeUnit.SECONDS);
+    builder.addInterceptor(new RateLimitInterceptor(rateLimit));
     // OkHttp's connection pooling is disabled because the HTTP plugin creates
     // and discards potentially many OkHttp clients, each leaving lingering
     // CLOSE_WAIT connections around if they have pooling enabled.
     builder.connectionPool(new ConnectionPool(0, 1, TimeUnit.SECONDS));
 
     // Code to skip SSL Certificate validation
-    // Sourced from 
https://stackoverflow.com/questions/60110848/how-to-disable-ssl-verification
     if (! apiConfig.verifySSLCert()) {
       try {
         TrustManager[] trustAllCerts = getAllTrustingTrustManager();
@@ -1023,6 +1026,38 @@ public class SimpleHttp implements AutoCloseable {
     }
   }
 
+  /**
+   * This interceptor is used in pagination situations or elsewhere when APIs 
have burst throttling. The rate limit interceptor
+   * will wait a configurable number of milliseconds and retry queries if it 
encounters a 429
+   * response code.
+   */
+  public static class RateLimitInterceptor implements Interceptor {
+    private final int millis;
+    public RateLimitInterceptor(int millis) {
+      this.millis = millis;
+    }
+
+    @NotNull
+    @Override
+    public Response intercept(Chain chain) throws IOException {
+
+      Response response = chain.proceed(chain.request());
+      // 429 is how the api indicates a rate limit error
+      if (!response.isSuccessful() && response.code() == 429) {
+        logger.info("Received 429 Response.  Throttling API calls: {} ", 
response.message());
+        // Wait and retry request
+        try {
+          Thread.sleep(millis);
+        } catch (InterruptedException e) {
+          logger.error("Error retrying HTTP request: {}", e.getMessage());
+        }
+        response = chain.proceed(chain.request());
+      }
+      return response;
+    }
+  }
+
+
   public static class SimpleHttpBuilder {
     private HttpSubScan scanDefn;
     private HttpUrl url;
@@ -1037,6 +1072,7 @@ public class SimpleHttp implements AutoCloseable {
     private Map<String,String> filters;
     private String connection;
     private String username;
+    private int rateLimit;
 
     public SimpleHttpBuilder scanDefn(HttpSubScan scanDefn) {
       this.scanDefn = scanDefn;
@@ -1046,6 +1082,7 @@ public class SimpleHttp implements AutoCloseable {
       this.tokenTable = scanDefn.tableSpec().getTokenTable();
       this.filters = scanDefn.filters();
       this.username = scanDefn.getUserName();
+      this.rateLimit = scanDefn.tableSpec().config().retryDelay();
       return this;
     }
 
@@ -1079,6 +1116,11 @@ public class SimpleHttp implements AutoCloseable {
       return this;
     }
 
+    public SimpleHttpBuilder rateLimit(int rateLimit) {
+      this.rateLimit = rateLimit;
+      return this;
+    }
+
     public SimpleHttpBuilder tokenTable(PersistentTokenTable tokenTable) {
       this.tokenTable = tokenTable;
       return this;
@@ -1105,12 +1147,11 @@ public class SimpleHttp implements AutoCloseable {
       return this;
     }
 
-
     public SimpleHttp build() {
       if (this.scanDefn != null) {
         return new SimpleHttp(scanDefn, url, tempDir, proxyConfig, 
errorContext, paginator);
       } else {
-        return new SimpleHttp(url, tempDir, proxyConfig, errorContext, 
paginator, tokenTable, pluginConfig, endpointConfig, connection, filters);
+        return new SimpleHttp(url, tempDir, proxyConfig, errorContext, 
paginator, tokenTable, pluginConfig, endpointConfig, connection, filters, 
rateLimit);
       }
     }
   }
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpPlugin.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpPlugin.java
index 928975f17a..c09e3a5503 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpPlugin.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpPlugin.java
@@ -138,7 +138,8 @@ public class TestHttpPlugin extends ClusterTest {
     configs.put("pokemon", pokemonConfig);
 
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-        new HttpStoragePluginConfig(false, configs, 10, null, null, "", 80, 
"", "", "", null, PlainCredentialsProvider.EMPTY_CREDENTIALS_PROVIDER, 
AuthMode.SHARED_USER.name());
+        new HttpStoragePluginConfig(false, configs, 10, 1000, null, null, "", 
80, "", "", "", null, PlainCredentialsProvider.EMPTY_CREDENTIALS_PROVIDER,
+          AuthMode.SHARED_USER.name());
     mockStorageConfigWithWorkspace.setEnabled(true);
     cluster.defineStoragePlugin("live", mockStorageConfigWithWorkspace);
   }
@@ -355,7 +356,7 @@ public class TestHttpPlugin extends ClusterTest {
     configs.put("malformedJson", mockJsonWithMalformedData);
 
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-        new HttpStoragePluginConfig(false, configs, 2, "globaluser", 
"globalpass", "",
+        new HttpStoragePluginConfig(false, configs, 2, 1000, "globaluser", 
"globalpass", "",
           80, "", "", "", null, new PlainCredentialsProvider(ImmutableMap.of(
           UsernamePasswordCredentials.USERNAME, "globaluser",
           UsernamePasswordCredentials.PASSWORD, "globalpass")), 
AuthMode.SHARED_USER.name());
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFFunctions.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFFunctions.java
index c5901b9087..e176d7c7c5 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFFunctions.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFFunctions.java
@@ -117,7 +117,7 @@ public class TestHttpUDFFunctions extends ClusterTest {
     configs.put("basicJson", basicJson);
 
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-      new HttpStoragePluginConfig(false, configs, 200, "globaluser", 
"globalpass", "",
+      new HttpStoragePluginConfig(false, configs, 200, 1000, "globaluser", 
"globalpass", "",
         80, "", "", "", null, new PlainCredentialsProvider(ImmutableMap.of(
         UsernamePasswordCredentials.USERNAME, "globaluser",
         UsernamePasswordCredentials.PASSWORD, "globalpass")), 
AuthMode.SHARED_USER.name());
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFWithAliases.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFWithAliases.java
index 15152de5cd..1bd574c1f7 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFWithAliases.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestHttpUDFWithAliases.java
@@ -116,7 +116,7 @@ public class TestHttpUDFWithAliases extends ClusterTest {
     configs.put("basicJson", basicJson);
 
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-      new HttpStoragePluginConfig(false, configs, 200, "globaluser", 
"globalpass", "",
+      new HttpStoragePluginConfig(false, configs, 200, 1000, "globaluser", 
"globalpass", "",
         80, "", "", "", null, new PlainCredentialsProvider(ImmutableMap.of(
         UsernamePasswordCredentials.USERNAME, "globaluser",
         UsernamePasswordCredentials.PASSWORD, "globalpass")), 
AuthMode.SHARED_USER.name());
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthProcess.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthProcess.java
index f38512d1df..695c60f5cb 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthProcess.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthProcess.java
@@ -111,7 +111,7 @@ public class TestOAuthProcess extends ClusterTest {
 
     // Add storage plugin for test OAuth
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-      new HttpStoragePluginConfig(false, configs, TIMEOUT, null, null, "", 80, 
"", "", "",
+      new HttpStoragePluginConfig(false, configs, TIMEOUT, 1000, null, null, 
"", 80, "", "", "",
         oAuthConfig, credentialsProvider, AuthMode.SHARED_USER.name());
     mockStorageConfigWithWorkspace.setEnabled(true);
     cluster.defineStoragePlugin("localOauth", mockStorageConfigWithWorkspace);
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthTokenUpdate.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthTokenUpdate.java
index 0490005d5b..2e818aec2b 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthTokenUpdate.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestOAuthTokenUpdate.java
@@ -91,7 +91,7 @@ public class TestOAuthTokenUpdate extends ClusterTest {
 
     // Add storage plugin for test OAuth
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-      new HttpStoragePluginConfig(false, configs, TIMEOUT,null, null, "", 80, 
"", "", "",
+      new HttpStoragePluginConfig(false, configs, TIMEOUT, 1000, null, null, 
"", 80, "", "", "",
         oAuthConfig, credentialsProvider, AuthMode.SHARED_USER.name());
     mockStorageConfigWithWorkspace.setEnabled(true);
     cluster.defineStoragePlugin("localOauth", mockStorageConfigWithWorkspace);
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestPagination.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestPagination.java
index d04f230f3d..2334315a3e 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestPagination.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestPagination.java
@@ -132,7 +132,7 @@ public class TestPagination extends ClusterTest {
     configs.put("github", githubConfig);
 
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-      new HttpStoragePluginConfig(false, configs, 10, null, null, "", 80, "", 
"", "", null,
+      new HttpStoragePluginConfig(false, configs, 10, 1000, null, null, "", 
80, "", "", "", null,
         PlainCredentialsProvider.EMPTY_CREDENTIALS_PROVIDER, 
AuthMode.SHARED_USER.name());
     mockStorageConfigWithWorkspace.setEnabled(true);
     cluster.defineStoragePlugin("live", mockStorageConfigWithWorkspace);
@@ -268,7 +268,7 @@ public class TestPagination extends ClusterTest {
     configs.put("xml_paginator_url_params", 
mockXmlConfigWithPaginatorAndUrlParams);
 
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-      new HttpStoragePluginConfig(false, configs, 2, null, null, "", 80, "", 
"", "", null,
+      new HttpStoragePluginConfig(false, configs, 2,1000, null, null, "", 80, 
"", "", "", null,
         PlainCredentialsProvider.EMPTY_CREDENTIALS_PROVIDER, 
AuthMode.SHARED_USER.name());
     mockStorageConfigWithWorkspace.setEnabled(true);
     cluster.defineStoragePlugin("local", mockStorageConfigWithWorkspace);
@@ -314,6 +314,33 @@ public class TestPagination extends ClusterTest {
     }
   }
 
+  @Test
+  public void simpleJSONPaginatorQueryWith429() throws Exception {
+    // This test simulates an http request that hits a burst limit.   In this 
situation,
+    // Drill will wait and retry the request.
+    String sql = "SELECT * FROM `local`.`json_paginator` LIMIT 4";
+    try (MockWebServer server = startServer()) {
+
+      server.enqueue(new 
MockResponse().setResponseCode(200).setBody(TEST_JSON_PAGE1));
+      server.enqueue(new MockResponse().setResponseCode(429));
+      server.enqueue(new 
MockResponse().setResponseCode(200).setBody(TEST_JSON_PAGE2));
+      server.enqueue(new MockResponse().setResponseCode(429));
+      server.enqueue(new 
MockResponse().setResponseCode(200).setBody(TEST_JSON_PAGE3));
+
+      List<QueryDataBatch> results = client.queryBuilder()
+        .sql(sql)
+        .results();
+
+      int count = 0;
+      for(QueryDataBatch b : results){
+        count += b.getHeader().getRowCount();
+        b.release();
+      }
+      assertEquals(2, results.size());
+      assertEquals(4, count);
+    }
+  }
+
   @Test
   public void simpleJSONIndexQuery() throws Exception {
     String sql = "SELECT * FROM `local`.`json_index` LIMIT 4";
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestProvidedSchema.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestProvidedSchema.java
index 1028668e10..281320c1aa 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestProvidedSchema.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestProvidedSchema.java
@@ -160,7 +160,7 @@ public class TestProvidedSchema extends ClusterTest {
     configs.put("noSchema", noSchema);
 
     HttpStoragePluginConfig mockStorageConfigWithWorkspace =
-      new HttpStoragePluginConfig(false, configs, 2, "globaluser", 
"globalpass", "",
+      new HttpStoragePluginConfig(false, configs, 2, 1000, "globaluser", 
"globalpass", "",
         80, "", "", "", null, new PlainCredentialsProvider(ImmutableMap.of(
         UsernamePasswordCredentials.USERNAME, "globaluser",
         UsernamePasswordCredentials.PASSWORD, "globalpass")), 
AuthMode.SHARED_USER.name());
diff --git 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestUserTranslationInHttpPlugin.java
 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestUserTranslationInHttpPlugin.java
index cb3c74c1e9..2252daee49 100644
--- 
a/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestUserTranslationInHttpPlugin.java
+++ 
b/contrib/storage-http/src/test/java/org/apache/drill/exec/store/http/TestUserTranslationInHttpPlugin.java
@@ -133,11 +133,11 @@ public class TestUserTranslationInHttpPlugin extends 
ClusterTest {
 
     PlainCredentialsProvider credentialsProvider = new 
PlainCredentialsProvider(TEST_USER_2, credentials);
 
-    HttpStoragePluginConfig mockStorageConfigWithWorkspace = new 
HttpStoragePluginConfig(false, configs, 2, null, null, "", 80, "", "", "", 
null, credentialsProvider,
+    HttpStoragePluginConfig mockStorageConfigWithWorkspace = new 
HttpStoragePluginConfig(false, configs, 2, 1000, null, null, "", 80, "", "", 
"", null, credentialsProvider,
       AuthMode.USER_TRANSLATION.name());
     mockStorageConfigWithWorkspace.setEnabled(true);
 
-    HttpStoragePluginConfig mockOAuthPlugin = new 
HttpStoragePluginConfig(false, configs, 2, null, null, "", 80, "", "", "", 
oAuthConfig, oauthCredentialProvider,
+    HttpStoragePluginConfig mockOAuthPlugin = new 
HttpStoragePluginConfig(false, configs, 2, 1000, null, null, "", 80, "", "", 
"", oAuthConfig, oauthCredentialProvider,
       AuthMode.USER_TRANSLATION.name());
     mockOAuthPlugin.setEnabled(true);
 

Reply via email to