Skip to content

Commit dc5787d

Browse files
refi64sjoerdsimons
authored andcommitted
Remove timeouts from OBS API requests
Since gitlab-runner-rs 0.0.7 now supports respecting job cancellation and timeouts from GitLab, so there isn't any reason to add additional timeouts to the API requests anymore. The tests do now need to have some timeouts set on them, since the retries would otherwise go on indefinitely. This slows them down a bit, so the single test function was refactored into 4 more fine-grained, that way they can run in parallel (it's a bit cleaner anyway). Signed-off-by: Ryan Gonzalez <ryan.gonzalez@collabora.com>
1 parent 1d9954c commit dc5787d

File tree

4 files changed

+83
-56
lines changed

4 files changed

+83
-56
lines changed

src/binaries.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use tokio::{fs::File as AsyncFile, io::AsyncSeekExt};
77
use tokio_util::compat::FuturesAsyncReadCompatExt;
88
use tracing::{info_span, instrument, Instrument};
99

10-
use crate::retry::{retry_large_request, retry_request};
10+
use crate::retry::retry_request;
1111

1212
#[instrument(skip(client))]
1313
pub async fn download_binaries(
@@ -28,7 +28,7 @@ pub async fn download_binaries(
2828
let mut binaries = HashMap::new();
2929

3030
for binary in binary_list.binaries {
31-
let mut dest = retry_large_request(|| {
31+
let mut dest = retry_request(|| {
3232
let binary = binary.clone();
3333
let client = client.clone();
3434
async move {

src/monitor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use tokio::{
1111
};
1212
use tracing::{debug, instrument};
1313

14-
use crate::retry::{retry_large_request, retry_request};
14+
use crate::retry::retry_request;
1515

1616
#[derive(Debug)]
1717
pub enum PackageCompletion {
@@ -245,7 +245,7 @@ impl ObsMonitor {
245245
pub async fn download_build_log(&self) -> Result<LogFile> {
246246
const LOG_LEN_TO_CHECK_FOR_MD5: u64 = 2500;
247247

248-
let mut file = retry_large_request(|| async {
248+
let mut file = retry_request(|| async {
249249
let mut file = AsyncFile::from_std(
250250
tempfile::tempfile().wrap_err("Failed to create tempfile to build log")?,
251251
);

src/retry.rs

Lines changed: 77 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use open_build_service_api as obs;
88
use tokio::sync::Mutex;
99
use tracing::instrument;
1010

11+
const INITIAL_INTERVAL: Duration = Duration::from_millis(300);
12+
1113
fn is_client_error(err: &(dyn std::error::Error + 'static)) -> bool {
1214
err.downcast_ref::<reqwest::Error>()
1315
.and_then(|e| e.status())
@@ -30,7 +32,8 @@ fn is_caused_by_client_error(report: &Report) -> bool {
3032
})
3133
}
3234

33-
async fn retry_request_impl<T, E, Fut, Func>(backoff_limit: Duration, func: Func) -> Result<T>
35+
#[instrument(skip(func))]
36+
pub async fn retry_request<T, E, Fut, Func>(func: Func) -> Result<T>
3437
where
3538
Fut: Future<Output = Result<T, E>>,
3639
Func: FnMut() -> Fut,
@@ -39,7 +42,8 @@ where
3942
let func = Arc::new(Mutex::new(func));
4043
backoff::future::retry(
4144
ExponentialBackoff {
42-
max_elapsed_time: Some(backoff_limit),
45+
max_elapsed_time: None,
46+
initial_interval: INITIAL_INTERVAL,
4347
..Default::default()
4448
},
4549
move || {
@@ -60,32 +64,11 @@ where
6064
.await
6165
}
6266

63-
#[instrument(skip(func))]
64-
pub async fn retry_request<T, E, Fut, Func>(func: Func) -> Result<T>
65-
where
66-
Fut: Future<Output = Result<T, E>>,
67-
Func: FnMut() -> Fut,
68-
E: Into<Report>,
69-
{
70-
const BACKOFF_LIMIT: Duration = Duration::from_secs(10 * 60); // 10 minutes
71-
retry_request_impl(BACKOFF_LIMIT, func).await
72-
}
73-
74-
#[instrument(skip(func))]
75-
pub async fn retry_large_request<T, E, Fut, Func>(func: Func) -> Result<T>
76-
where
77-
Fut: Future<Output = Result<T, E>>,
78-
Func: FnMut() -> Fut,
79-
E: Into<Report>,
80-
{
81-
const BACKOFF_LIMIT: Duration = Duration::from_secs(60 * 60); // 1 hour
82-
retry_request_impl(BACKOFF_LIMIT, func).await
83-
}
84-
8567
#[cfg(test)]
8668
mod tests {
8769
use claim::*;
8870
use open_build_service_api as obs;
71+
use rstest::*;
8972
use wiremock::{
9073
matchers::{method, path_regex},
9174
Mock, MockServer, ResponseTemplate,
@@ -95,10 +78,12 @@ mod tests {
9578

9679
use super::*;
9780

98-
const LIMIT: Duration = Duration::from_secs(1);
81+
fn wrap_in_io_error(err: obs::Error) -> std::io::Error {
82+
std::io::Error::new(std::io::ErrorKind::Other, err)
83+
}
9984

100-
#[tokio::test]
101-
async fn test_retry_on_non_client_errors() {
85+
#[fixture]
86+
async fn server() -> MockServer {
10287
let server = MockServer::start().await;
10388

10489
Mock::given(method("GET"))
@@ -116,6 +101,13 @@ mod tests {
116101
.mount(&server)
117102
.await;
118103

104+
server
105+
}
106+
107+
#[rstest]
108+
#[tokio::test]
109+
async fn test_retry_on_non_client_errors(server: impl Future<Output = MockServer>) {
110+
let server = server.await;
119111
let client = obs::Client::new(
120112
server.uri().parse().unwrap(),
121113
TEST_USER.to_owned(),
@@ -124,50 +116,89 @@ mod tests {
124116

125117
let mut attempts = 0;
126118
assert_err!(
127-
retry_request_impl(LIMIT, || {
128-
attempts += 1;
129-
async { client.project("500".to_owned()).meta().await }
130-
})
119+
tokio::time::timeout(
120+
Duration::from_millis(2000),
121+
retry_request(|| {
122+
attempts += 1;
123+
async { client.project("500".to_owned()).meta().await }
124+
})
125+
)
131126
.await
132127
);
133128
assert_gt!(attempts, 1);
129+
}
130+
131+
#[rstest]
132+
#[tokio::test]
133+
async fn test_retry_on_nested_non_client_errors(server: impl Future<Output = MockServer>) {
134+
let server = server.await;
135+
let client = obs::Client::new(
136+
server.uri().parse().unwrap(),
137+
TEST_USER.to_owned(),
138+
TEST_PASS.to_owned(),
139+
);
134140

135141
let mut attempts = 0;
136142
assert_err!(
137-
retry_request_impl(LIMIT, || {
138-
attempts += 1;
139-
async {
140-
client
141-
.project("500".to_owned())
142-
.meta()
143-
.await
144-
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
145-
}
146-
})
143+
tokio::time::timeout(
144+
Duration::from_millis(2000),
145+
retry_request(|| {
146+
attempts += 1;
147+
async {
148+
client
149+
.project("500".to_owned())
150+
.meta()
151+
.await
152+
.map_err(wrap_in_io_error)
153+
}
154+
})
155+
)
147156
.await
148157
);
149158
assert_gt!(attempts, 1);
159+
}
150160

151-
attempts = 0;
161+
#[rstest]
162+
#[tokio::test]
163+
async fn test_no_retry_on_client_errors(server: impl Future<Output = MockServer>) {
164+
let server = server.await;
165+
let client = obs::Client::new(
166+
server.uri().parse().unwrap(),
167+
TEST_USER.to_owned(),
168+
TEST_PASS.to_owned(),
169+
);
170+
171+
let mut attempts = 0;
152172
assert_err!(
153-
retry_request_impl(LIMIT, || {
173+
retry_request(|| {
154174
attempts += 1;
155175
async { client.project("403".to_owned()).meta().await }
156176
})
157177
.await
158178
);
159179
assert_eq!(attempts, 1);
180+
}
160181

161-
attempts = 0;
182+
#[rstest]
183+
#[tokio::test]
184+
async fn test_no_retry_on_nested_client_errors(server: impl Future<Output = MockServer>) {
185+
let server = server.await;
186+
let client = obs::Client::new(
187+
server.uri().parse().unwrap(),
188+
TEST_USER.to_owned(),
189+
TEST_PASS.to_owned(),
190+
);
191+
192+
let mut attempts = 0;
162193
assert_err!(
163-
retry_request_impl(LIMIT, || {
194+
retry_request(|| {
164195
attempts += 1;
165196
async {
166197
client
167198
.project("403".to_owned())
168199
.meta()
169200
.await
170-
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
201+
.map_err(wrap_in_io_error)
171202
}
172203
})
173204
.await

src/upload.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ use md5::{Digest, Md5};
1010
use open_build_service_api as obs;
1111
use tracing::{debug, info_span, instrument, trace, Instrument};
1212

13-
use crate::{
14-
artifacts::ArtifactDirectory,
15-
dsc::Dsc,
16-
retry::{retry_large_request, retry_request},
17-
};
13+
use crate::{artifacts::ArtifactDirectory, dsc::Dsc, retry::retry_request};
1814

1915
type Md5String = String;
2016

@@ -234,7 +230,7 @@ impl ObsDscUploader {
234230
debug!("Uploading file");
235231
let file = artifacts.get_file(root.join(filename).as_str()).await?;
236232

237-
retry_large_request(|| {
233+
retry_request(|| {
238234
file.try_clone().then(|file| async {
239235
let file = file.wrap_err("Failed to clone file")?;
240236
self.client

0 commit comments

Comments
 (0)