Skip to content

Commit a81f6c1

Browse files
committed
fix for issue redouane59#440 and improved rate limit handling
1 parent 19134de commit a81f6c1

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

src/main/java/io/github/redouane59/twitter/helpers/AbstractRequestHelper.java

+29-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public abstract class AbstractRequestHelper {
3131
private final OAuth10aService service;
3232
@Setter
3333
private boolean automaticRetry = true;
34+
35+
private long lastCallTs;
3436

3537
protected AbstractRequestHelper(TwitterCredentials twitterCredentials) {
3638
this(twitterCredentials, new ServiceBuilder(twitterCredentials.getApiKey())
@@ -82,19 +84,42 @@ public <T> Optional<T> makeRequest(OAuthRequest request, boolean signRequired, C
8284
if (signRequired) {
8385
signRequest(request);
8486
}
87+
// endpoint /2/tweets/search/all has a one request per second rate limit, see https://developer.twitter.com/en/docs/twitter-api/tweets/search/api-reference/get-tweets-search-all
88+
if(request.getUrl().contains("/2/tweets/search/all")) {
89+
long now = System.currentTimeMillis();
90+
if(now < (lastCallTs+1000)) {
91+
int sleepTime= 1000-Math.toIntExact(now-lastCallTs);
92+
LOGGER.trace("sleep {}ms between two calls on /search/all", sleepTime);
93+
Thread.sleep(sleepTime);
94+
lastCallTs = now+sleepTime;
95+
} else {
96+
lastCallTs = now;
97+
}
98+
99+
}
85100
try (Response response = getService().execute(request)) {
86101
String stringResponse = response.getBody();
102+
LOGGER.debug("Response code: {} to url: '{}' headers: x-rate-limit-reset: {} x-rate-limit-remaining: {}", response.getCode(), request.getUrl(), response.getHeader("x-rate-limit-reset"), response.getHeader("x-rate-limit-remaining"));
103+
87104
if (response.getCode() == 429) {
88105
if (!automaticRetry) {
89106
throw new LimitExceededException(response.getHeader("x-rate-limit-reset"));
90107
}
91108
int retryAfter = DEFAULT_RETRY_AFTER_SEC;
92109
String retryAfterStr = response.getHeader("x-rate-limit-reset");
93-
if (retryAfterStr != null) {
110+
String rateRemainingStr = response.getHeader("x-rate-limit-remaining");
111+
LOGGER.trace("Rate limit exceeded, x-rate-limit-reset: {} x-rate-limit-remaining: {}, x-rate-limit-limit: {}", retryAfterStr, response.getHeader("x-rate-limit-remaining"), response.getHeader("x-rate-limit-limit"));
112+
if (retryAfterStr != null && rateRemainingStr != null) {
94113
try {
95-
long resetTime = Long.parseLong(retryAfterStr);
96-
long currentTime = (new Date().getTime()) / 1000;
97-
retryAfter = Math.toIntExact(resetTime - currentTime);
114+
int remaining = Integer.parseInt(rateRemainingStr);
115+
if(remaining>0) { //if we have remaining requests in this slot, the rate limit has been raised due to more calls than one per second. e.g. /search/all endpoint
116+
retryAfter=1; //wait one second
117+
} else {
118+
long resetTime = Long.parseLong(retryAfterStr);
119+
long currentTime = (new Date().getTime()) / 1000;
120+
retryAfter = Math.toIntExact(resetTime - currentTime);
121+
if(retryAfter<0) retryAfter=1; //issue #440 ( negative sleep time)
122+
}
98123
} catch (NumberFormatException e) {
99124
LOGGER.error("Using default retry after because header format is invalid: {}", retryAfterStr, e);
100125
}

0 commit comments

Comments
 (0)