Skip to content

Commit 88eb560

Browse files
authored
Add support for global and per call request timeouts (#132)
This commit adds the ability to support a global request timeout on TransportBuilder, as well as per request timeouts on builder structs. Closes #116
1 parent fa220df commit 88eb560

31 files changed

+2901
-315
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
238238
HeaderMap::new(),
239239
Option::<&Value>::None,
240240
Some(body.as_ref()),
241+
None,
241242
)
242243
.await?;
243244
Ok(())

api_generator/src/generator/code_gen/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ pub fn use_declarations() -> Tokens {
4343
transport::Transport,
4444
},
4545
};
46-
use std::borrow::Cow;
46+
use std::{
47+
borrow::Cow,
48+
time::Duration
49+
};
4750
use percent_encoding::percent_encode;
4851
use serde::Serialize;
4952
)

api_generator/src/generator/code_gen/request/request_builder.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,43 @@ impl<'a> RequestBuilder<'a> {
350350
}
351351
}
352352

353+
/// Creates the AST for a builder fn to add a request timeout
354+
fn create_request_timeout_fn(field: &syn::Ident) -> syn::ImplItem {
355+
let doc_attr = doc("Sets a request timeout for this API call.\n\nThe timeout is applied from when the request starts connecting until the response body has finished.");
356+
357+
syn::ImplItem {
358+
ident: ident("request_timeout"),
359+
vis: syn::Visibility::Public,
360+
defaultness: syn::Defaultness::Final,
361+
attrs: vec![doc_attr],
362+
node: syn::ImplItemKind::Method(
363+
syn::MethodSig {
364+
unsafety: syn::Unsafety::Normal,
365+
constness: syn::Constness::NotConst,
366+
abi: None,
367+
decl: syn::FnDecl {
368+
inputs: vec![
369+
syn::FnArg::SelfValue(syn::Mutability::Mutable),
370+
syn::FnArg::Captured(
371+
syn::Pat::Path(None, path_none("timeout")),
372+
syn::parse_type("Duration").unwrap(),
373+
),
374+
],
375+
output: syn::FunctionRetTy::Ty(code_gen::ty("Self")),
376+
variadic: false,
377+
},
378+
generics: generics_none(),
379+
},
380+
syn::Block {
381+
stmts: vec![
382+
syn::Stmt::Semi(Box::new(parse_expr(quote!(self.#field = Some(timeout))))),
383+
syn::Stmt::Expr(Box::new(parse_expr(quote!(self)))),
384+
],
385+
},
386+
),
387+
}
388+
}
389+
353390
/// Creates the AST for a builder fn for a builder impl
354391
fn create_impl_fn(f: (&String, &Type)) -> syn::ImplItem {
355392
let name = valid_name(&f.0).to_lowercase();
@@ -456,6 +493,7 @@ impl<'a> RequestBuilder<'a> {
456493
.collect();
457494

458495
let headers_field_ident = ident("headers");
496+
let request_timeout_ident = ident("request_timeout");
459497

460498
// add a field for HTTP headers
461499
fields.push(syn::Field {
@@ -464,6 +502,12 @@ impl<'a> RequestBuilder<'a> {
464502
attrs: vec![],
465503
ty: syn::parse_type("HeaderMap").unwrap(),
466504
});
505+
fields.push(syn::Field {
506+
ident: Some(request_timeout_ident.clone()),
507+
vis: syn::Visibility::Inherited,
508+
attrs: vec![],
509+
ty: syn::parse_type("Option<Duration>").unwrap(),
510+
});
467511

468512
if supports_body {
469513
fields.push(syn::Field {
@@ -491,6 +535,7 @@ impl<'a> RequestBuilder<'a> {
491535
endpoint.params.iter().map(Self::create_impl_fn).collect();
492536

493537
builder_fns.push(Self::create_header_fn(&headers_field_ident));
538+
builder_fns.push(Self::create_request_timeout_fn(&request_timeout_ident));
494539

495540
// add a body impl if supported
496541
if supports_body {
@@ -591,9 +636,10 @@ impl<'a> RequestBuilder<'a> {
591636
let path = self.parts.url();
592637
let method = #method_expr;
593638
let headers = self.headers;
639+
let timeout = self.request_timeout;
594640
let query_string = #query_string_expr;
595641
let body = #body_expr;
596-
let response = self.transport.send(method, &path, headers, query_string.as_ref(), body).await?;
642+
let response = self.transport.send(method, &path, headers, query_string.as_ref(), body, timeout).await?;
597643
Ok(response)
598644
}
599645
}

elasticsearch/src/client.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::{
2222
};
2323

2424
use serde::{Serialize, Serializer};
25+
use std::time::Duration;
2526

2627
/// Serializes an `Option<&[Serialize]>` with
2728
/// `Some(value)` to a comma separated string of values.
@@ -80,13 +81,14 @@ impl Elasticsearch {
8081
headers: HeaderMap,
8182
query_string: Option<&Q>,
8283
body: Option<B>,
84+
timeout: Option<Duration>,
8385
) -> Result<Response, Error>
8486
where
8587
B: Body,
8688
Q: Serialize + ?Sized,
8789
{
8890
self.transport
89-
.send(method, path, headers, query_string, body)
91+
.send(method, path, headers, query_string, body, timeout)
9092
.await
9193
}
9294
}

elasticsearch/src/generated/namespace_clients/async_search.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::{
3737
};
3838
use percent_encoding::percent_encode;
3939
use serde::Serialize;
40-
use std::borrow::Cow;
40+
use std::{borrow::Cow, time::Duration};
4141
#[derive(Debug, Clone, PartialEq)]
4242
#[doc = "API parts for the Async Search Delete API"]
4343
pub enum AsyncSearchDeleteParts<'b> {
@@ -68,6 +68,7 @@ pub struct AsyncSearchDelete<'a, 'b> {
6868
headers: HeaderMap,
6969
human: Option<bool>,
7070
pretty: Option<bool>,
71+
request_timeout: Option<Duration>,
7172
source: Option<&'b str>,
7273
}
7374
impl<'a, 'b> AsyncSearchDelete<'a, 'b> {
@@ -82,6 +83,7 @@ impl<'a, 'b> AsyncSearchDelete<'a, 'b> {
8283
filter_path: None,
8384
human: None,
8485
pretty: None,
86+
request_timeout: None,
8587
source: None,
8688
}
8789
}
@@ -110,6 +112,11 @@ impl<'a, 'b> AsyncSearchDelete<'a, 'b> {
110112
self.pretty = Some(pretty);
111113
self
112114
}
115+
#[doc = "Sets a request timeout for this API call.\n\nThe timeout is applied from when the request starts connecting until the response body has finished."]
116+
pub fn request_timeout(mut self, timeout: Duration) -> Self {
117+
self.request_timeout = Some(timeout);
118+
self
119+
}
113120
#[doc = "The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests."]
114121
pub fn source(mut self, source: &'b str) -> Self {
115122
self.source = Some(source);
@@ -120,6 +127,7 @@ impl<'a, 'b> AsyncSearchDelete<'a, 'b> {
120127
let path = self.parts.url();
121128
let method = Method::Delete;
122129
let headers = self.headers;
130+
let timeout = self.request_timeout;
123131
let query_string = {
124132
#[serde_with::skip_serializing_none]
125133
#[derive(Serialize)]
@@ -150,7 +158,7 @@ impl<'a, 'b> AsyncSearchDelete<'a, 'b> {
150158
let body = Option::<()>::None;
151159
let response = self
152160
.transport
153-
.send(method, &path, headers, query_string.as_ref(), body)
161+
.send(method, &path, headers, query_string.as_ref(), body, timeout)
154162
.await?;
155163
Ok(response)
156164
}
@@ -186,6 +194,7 @@ pub struct AsyncSearchGet<'a, 'b> {
186194
human: Option<bool>,
187195
keep_alive: Option<&'b str>,
188196
pretty: Option<bool>,
197+
request_timeout: Option<Duration>,
189198
source: Option<&'b str>,
190199
typed_keys: Option<bool>,
191200
wait_for_completion_timeout: Option<&'b str>,
@@ -203,6 +212,7 @@ impl<'a, 'b> AsyncSearchGet<'a, 'b> {
203212
human: None,
204213
keep_alive: None,
205214
pretty: None,
215+
request_timeout: None,
206216
source: None,
207217
typed_keys: None,
208218
wait_for_completion_timeout: None,
@@ -238,6 +248,11 @@ impl<'a, 'b> AsyncSearchGet<'a, 'b> {
238248
self.pretty = Some(pretty);
239249
self
240250
}
251+
#[doc = "Sets a request timeout for this API call.\n\nThe timeout is applied from when the request starts connecting until the response body has finished."]
252+
pub fn request_timeout(mut self, timeout: Duration) -> Self {
253+
self.request_timeout = Some(timeout);
254+
self
255+
}
241256
#[doc = "The URL-encoded request definition. Useful for libraries that do not accept a request body for non-POST requests."]
242257
pub fn source(mut self, source: &'b str) -> Self {
243258
self.source = Some(source);
@@ -258,6 +273,7 @@ impl<'a, 'b> AsyncSearchGet<'a, 'b> {
258273
let path = self.parts.url();
259274
let method = Method::Get;
260275
let headers = self.headers;
276+
let timeout = self.request_timeout;
261277
let query_string = {
262278
#[serde_with::skip_serializing_none]
263279
#[derive(Serialize)]
@@ -297,7 +313,7 @@ impl<'a, 'b> AsyncSearchGet<'a, 'b> {
297313
let body = Option::<()>::None;
298314
let response = self
299315
.transport
300-
.send(method, &path, headers, query_string.as_ref(), body)
316+
.send(method, &path, headers, query_string.as_ref(), body, timeout)
301317
.await?;
302318
Ok(response)
303319
}
@@ -362,6 +378,7 @@ pub struct AsyncSearchSubmit<'a, 'b, B> {
362378
pretty: Option<bool>,
363379
q: Option<&'b str>,
364380
request_cache: Option<bool>,
381+
request_timeout: Option<Duration>,
365382
routing: Option<&'b [&'b str]>,
366383
search_type: Option<SearchType>,
367384
seq_no_primary_term: Option<bool>,
@@ -421,6 +438,7 @@ where
421438
pretty: None,
422439
q: None,
423440
request_cache: None,
441+
request_timeout: None,
424442
routing: None,
425443
search_type: None,
426444
seq_no_primary_term: None,
@@ -519,6 +537,7 @@ where
519537
pretty: self.pretty,
520538
q: self.q,
521539
request_cache: self.request_cache,
540+
request_timeout: self.request_timeout,
522541
routing: self.routing,
523542
search_type: self.search_type,
524543
seq_no_primary_term: self.seq_no_primary_term,
@@ -640,6 +659,11 @@ where
640659
self.request_cache = Some(request_cache);
641660
self
642661
}
662+
#[doc = "Sets a request timeout for this API call.\n\nThe timeout is applied from when the request starts connecting until the response body has finished."]
663+
pub fn request_timeout(mut self, timeout: Duration) -> Self {
664+
self.request_timeout = Some(timeout);
665+
self
666+
}
643667
#[doc = "A comma-separated list of specific routing values"]
644668
pub fn routing(mut self, routing: &'b [&'b str]) -> Self {
645669
self.routing = Some(routing);
@@ -740,6 +764,7 @@ where
740764
let path = self.parts.url();
741765
let method = Method::Post;
742766
let headers = self.headers;
767+
let timeout = self.request_timeout;
743768
let query_string = {
744769
#[serde_with::skip_serializing_none]
745770
#[derive(Serialize)]
@@ -914,7 +939,7 @@ where
914939
let body = self.body;
915940
let response = self
916941
.transport
917-
.send(method, &path, headers, query_string.as_ref(), body)
942+
.send(method, &path, headers, query_string.as_ref(), body, timeout)
918943
.await?;
919944
Ok(response)
920945
}

0 commit comments

Comments
 (0)