Skip to content

Commit e53bc13

Browse files
committed
feat(dart): endpoint level timeout
1 parent 1da1e81 commit e53bc13

File tree

7 files changed

+58
-2
lines changed

7 files changed

+58
-2
lines changed

clients/algoliasearch-client-dart/packages/client_core/lib/src/transport/dio/dio_requester.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,12 @@ class DioRequester implements Requester {
121121
void setClientApiKey(String apiKey) {
122122
_authInterceptor.apiKey = apiKey;
123123
}
124+
125+
@override
126+
get connectTimeout => _client.options.connectTimeout;
127+
128+
@override
129+
void setConnectTimeout(Duration connectTimeout) {
130+
_client.options.connectTimeout = connectTimeout;
131+
}
124132
}

clients/algoliasearch-client-dart/packages/client_core/lib/src/transport/request_options.dart

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ final class RequestOptions {
66
/// The read timeout for the request in milliseconds.
77
final Duration? readTimeout;
88

9+
/// The connect timeout for the request in milliseconds.
10+
final Duration? connectTimeout;
11+
912
/// Header names to their respective values to be sent with the request.
1013
final Map<String, dynamic> headers;
1114

@@ -18,18 +21,35 @@ final class RequestOptions {
1821
const RequestOptions({
1922
this.writeTimeout,
2023
this.readTimeout,
24+
this.connectTimeout,
2125
this.headers = const {},
2226
this.urlParameters = const {},
2327
this.body,
2428
});
2529

30+
RequestOptions operator +(RequestOptions? other) {
31+
if (other == null) {
32+
return this;
33+
}
34+
35+
return RequestOptions(
36+
writeTimeout: other.writeTimeout ?? writeTimeout,
37+
readTimeout: other.readTimeout ?? readTimeout,
38+
connectTimeout: other.connectTimeout ?? connectTimeout,
39+
headers: {...headers, ...other.headers},
40+
urlParameters: {...urlParameters, ...other.urlParameters},
41+
body: other.body ?? body,
42+
);
43+
}
44+
2645
@override
2746
bool operator ==(Object other) =>
2847
identical(this, other) ||
2948
other is RequestOptions &&
3049
runtimeType == other.runtimeType &&
3150
writeTimeout == other.writeTimeout &&
3251
readTimeout == other.readTimeout &&
52+
connectTimeout == other.connectTimeout &&
3353
headers == other.headers &&
3454
urlParameters == other.urlParameters &&
3555
body == other.body;
@@ -38,12 +58,13 @@ final class RequestOptions {
3858
int get hashCode =>
3959
writeTimeout.hashCode ^
4060
readTimeout.hashCode ^
61+
connectTimeout.hashCode ^
4162
headers.hashCode ^
4263
urlParameters.hashCode ^
4364
body.hashCode;
4465

4566
@override
4667
String toString() {
47-
return 'RequestOptions{writeTimeout: $writeTimeout, readTimeout: $readTimeout, headers: $headers, urlParameters: $urlParameters, body: $body}';
68+
return 'RequestOptions{writeTimeout: $writeTimeout, readTimeout: $readTimeout, connectTimeout: $connectTimeout, headers: $headers, urlParameters: $urlParameters, body: $body}';
4869
}
4970
}

clients/algoliasearch-client-dart/packages/client_core/lib/src/transport/requester.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ abstract class Requester {
1414
/// Allows to switch the API key used to authenticate requests.
1515
void setClientApiKey(String apiKey);
1616

17+
/// Allows to customise the connect timeout for the requester.
18+
get connectTimeout => null;
19+
void setConnectTimeout(Duration connectTimeout);
20+
1721
/// Closes any underlying resources that the Requester might be using.
1822
///
1923
/// By default, it does nothing (no-op), but it can be implemented to handle resource cleanup

clients/algoliasearch-client-dart/packages/client_core/lib/src/transport/retry_strategy.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ final class RetryStrategy {
5353
final List<AlgoliaException> errors = [];
5454
for (final host in hosts) {
5555
final httpRequest = _buildRequest(host, request, callType, options);
56+
final requesterConnectTimeout = requester.connectTimeout;
57+
if (options?.connectTimeout != null) {
58+
requester.setConnectTimeout(options!.connectTimeout!);
59+
}
5660
try {
5761
final response = await requester.perform(httpRequest);
62+
requester.setConnectTimeout(requesterConnectTimeout);
5863
return response.body ?? const {};
5964
} on AlgoliaTimeoutException catch (e) {
6065
host.timedOut();

generators/src/main/java/com/algolia/codegen/AlgoliaDartGenerator.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import static org.apache.commons.lang3.StringUtils.*;
44

5+
import com.algolia.codegen.lambda.ToSecondsLambda;
56
import com.algolia.codegen.utils.*;
7+
import com.google.common.collect.ImmutableMap;
8+
import com.samskivert.mustache.Mustache;
69
import io.swagger.v3.oas.models.OpenAPI;
710
import io.swagger.v3.oas.models.Operation;
811
import io.swagger.v3.oas.models.servers.Server;
@@ -109,6 +112,11 @@ public void processOpts() {
109112
additionalProperties.put("packageVersion", version);
110113
}
111114

115+
@Override
116+
protected ImmutableMap.Builder<String, Mustache.Lambda> addMustacheLambdas() {
117+
return super.addMustacheLambdas().put("toSeconds", new ToSecondsLambda());
118+
}
119+
112120
@Override
113121
public void processOpenAPI(OpenAPI openAPI) {
114122
super.processOpenAPI(openAPI);

templates/dart/api.mustache

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,11 @@ final class {{classname}} implements ApiClient {
165165
);
166166
{{#returnType}}final response = {{/returnType}}await _retryStrategy.execute(
167167
request: request,
168-
options: requestOptions,
168+
options: {{#vendorExtensions.x-timeouts}}new RequestOptions(
169+
writeTimeout: Duration(seconds: {{#lambda.toSeconds}}{{{write}}}{{/lambda.toSeconds}}),
170+
readTimeout: Duration(seconds: {{#lambda.toSeconds}}{{{read}}}{{/lambda.toSeconds}}),
171+
connectTimeout: Duration(seconds: {{#lambda.toSeconds}}{{{connect}}}{{/lambda.toSeconds}}),
172+
) + {{/vendorExtensions.x-timeouts}}requestOptions,
169173
);
170174
{{#returnType}}
171175
return deserialize<{{{.}}}, {{{returnBaseType}}}>(response, '{{{.}}}', growable: true,);

tests/output/dart/lib/src/run.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Future<void> runTest<T extends ApiClient>({
2525
/// Uses provided function to intercept HTTP requests.
2626
class RequestInterceptor extends Requester {
2727
String apiKey = "fake";
28+
Duration connectTimeout = Duration(seconds: 30);
2829

2930
Function(HttpRequest) onRequest = (_) {};
3031

@@ -46,6 +47,11 @@ class RequestInterceptor extends Requester {
4647
void setClientApiKey(String apiKey) {
4748
this.apiKey = apiKey;
4849
}
50+
51+
@override
52+
void setConnectTimeout(Duration connectTimeout) {
53+
this.connectTimeout = connectTimeout;
54+
}
4955
}
5056

5157
/// [InterceptionException] implements [Exception].

0 commit comments

Comments
 (0)