Skip to content

Commit f32f8c0

Browse files
authored
Make maxRequests and maxRequestsPerHost configurable (#1009)
1 parent 0596c4c commit f32f8c0

File tree

2 files changed

+91
-8
lines changed

2 files changed

+91
-8
lines changed

clients/line-bot-client-base/src/main/java/com/linecorp/bot/client/base/ApiClientBuilder.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.linecorp.bot.client.base.http.HttpResponse;
3737
import com.linecorp.bot.jackson.ModelObjectMapper;
3838

39+
import okhttp3.Dispatcher;
3940
import okhttp3.Interceptor;
4041
import okhttp3.OkHttpClient;
4142
import okhttp3.Request;
@@ -92,6 +93,10 @@ public ApiClientBuilder(URI apiEndPoint, Class<T> clientClass, ExceptionBuilder
9293

9394
private HttpAuthenticator proxyAuthenticator;
9495

96+
private Integer maxRequests = 64;
97+
98+
private Integer maxRequestsPerHost = 5;
99+
95100
/**
96101
* API Endpoint.
97102
*/
@@ -134,6 +139,25 @@ public ApiClientBuilder<T> addInterceptor(HttpInterceptor interceptor) {
134139
return this;
135140
}
136141

142+
/**
143+
* The maximum number of requests to execute concurrently.
144+
* Default: 64
145+
*/
146+
public ApiClientBuilder<T> maxRequests(Integer maxRequests) {
147+
this.maxRequests = maxRequests;
148+
return this;
149+
}
150+
151+
/**
152+
* The maximum number of requests for each host to execute concurrently.
153+
* Default: 5
154+
*/
155+
// https://square.github.io/okhttp/4.x/okhttp/okhttp3/-dispatcher/max-requests-per-host/
156+
public ApiClientBuilder<T> maxRequestsPerHost(Integer maxRequestsPerHost) {
157+
this.maxRequestsPerHost = maxRequestsPerHost;
158+
return this;
159+
}
160+
137161
private static Interceptor buildLoggingInterceptor() {
138162
final Logger slf4jLogger = LoggerFactory.getLogger("com.linecorp.bot.client.wire");
139163

@@ -151,11 +175,21 @@ public ApiClientBuilder<T> proxyAuthenticator(HttpAuthenticator proxyAuthenticat
151175
return this;
152176
}
153177

178+
// visible for testing
179+
OkHttpClient.Builder createBuilder() {
180+
return new OkHttpClient.Builder();
181+
}
182+
183+
// visible for testing
184+
Dispatcher createDispatcher() {
185+
return new Dispatcher();
186+
}
187+
154188
/**
155189
* Creates a new Client.
156190
*/
157191
public T build() {
158-
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
192+
OkHttpClient.Builder okHttpClientBuilder = createBuilder();
159193
additionalInterceptors.forEach(okHttpClientBuilder::addInterceptor);
160194
okHttpClientBuilder.addInterceptor(buildLoggingInterceptor());
161195

@@ -165,6 +199,12 @@ public T build() {
165199
.readTimeout(readTimeout)
166200
.writeTimeout(writeTimeout);
167201

202+
// configure dispatcher
203+
Dispatcher dispatcher = createDispatcher();
204+
dispatcher.setMaxRequests(maxRequests);
205+
dispatcher.setMaxRequestsPerHost(maxRequestsPerHost);
206+
okHttpClientBuilder.dispatcher(dispatcher);
207+
168208
// Error handling.
169209
okHttpClientBuilder.addInterceptor(chain -> {
170210
Request request = chain.request();
@@ -197,13 +237,19 @@ public T build() {
197237
return retrofit.create(clientClass);
198238
}
199239

240+
@Override
200241
public String toString() {
201-
return "ApiClientBuilder(clientClass=" + this.clientClass
202-
+ ", apiEndPoint=" + this.apiEndPoint
203-
+ ", connectTimeout=" + this.connectTimeout
204-
+ ", readTimeout=" + this.readTimeout
205-
+ ", writeTimeout=" + this.writeTimeout
206-
+ ", additionalInterceptors=" + this.additionalInterceptors
207-
+ ")";
242+
return "ApiClientBuilder{"
243+
+ "objectMapper=" + objectMapper
244+
+ ", clientClass=" + clientClass
245+
+ ", exceptionBuilder=" + exceptionBuilder
246+
+ ", apiEndPoint=" + apiEndPoint
247+
+ ", connectTimeout=" + connectTimeout
248+
+ ", readTimeout=" + readTimeout
249+
+ ", writeTimeout=" + writeTimeout
250+
+ ", additionalInterceptors=" + additionalInterceptors
251+
+ ", maxRequests=" + maxRequests
252+
+ ", maxRequestsPerHost=" + maxRequestsPerHost
253+
+ '}';
208254
}
209255
}

clients/line-bot-client-base/src/test/java/com/linecorp/bot/client/base/ApiClientBuilderTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathTemplate;
2323
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
2424
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.mockito.Mockito.spy;
26+
import static org.mockito.Mockito.verify;
2527

2628
import java.io.IOException;
2729
import java.net.InetSocketAddress;
@@ -37,6 +39,8 @@
3739
import com.github.tomakehurst.wiremock.WireMockServer;
3840
import com.github.tomakehurst.wiremock.client.WireMock;
3941

42+
import okhttp3.Dispatcher;
43+
import okhttp3.OkHttpClient;
4044
import okhttp3.Response;
4145
import retrofit2.http.GET;
4246

@@ -163,4 +167,37 @@ public static class MyClientException extends IOException {
163167
MyClientException() {
164168
}
165169
}
170+
171+
interface Foo {
172+
}
173+
174+
@Test
175+
void maxRequests() {
176+
OkHttpClient.Builder builder = spy(OkHttpClient.Builder.class);
177+
Dispatcher dispatcher = spy(Dispatcher.class);
178+
179+
ApiClientBuilder<Foo> apiClientBuilder = new ApiClientBuilder<>(URI.create("https://example.com"), Foo.class, new ExceptionBuilder() {
180+
@Override
181+
public IOException build(Response response) {
182+
return null;
183+
}
184+
}) {
185+
@Override
186+
OkHttpClient.Builder createBuilder() {
187+
return builder;
188+
}
189+
190+
@Override
191+
Dispatcher createDispatcher() {
192+
return dispatcher;
193+
}
194+
};
195+
apiClientBuilder.maxRequests(40)
196+
.maxRequestsPerHost(30)
197+
.build();
198+
199+
verify(dispatcher).setMaxRequests(40);
200+
verify(dispatcher).setMaxRequestsPerHost(30);
201+
verify(builder).dispatcher(dispatcher);
202+
}
166203
}

0 commit comments

Comments
 (0)