Skip to content

Commit 9876625

Browse files
committed
Add S3 timeout config to bottomless replicator and fix integration tests
- Add LIBSQL_BOTTOMLESS_S3_READ_TIMEOUT_SECS (default 5s) - Add LIBSQL_BOTTOMLESS_S3_CONNECT_TIMEOUT_SECS (default 5s) - Add LIBSQL_BOTTOMLESS_S3_OPERATION_ATTEMPT_TIMEOUT_SECS (default 10s) - Configure TimeoutConfig on aws_sdk_s3::Config in bottomless::replicator::Options::client_config() - Update meta_store.rs Options construction to include new timeout fields - Remove #[ignore] from network_partition test - Fix test fixtures: endpoint timing, image caching, mut minio
1 parent bdb1746 commit 9876625

9 files changed

Lines changed: 137 additions & 43 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ libsql-sqlite3/**.o.tmp
1212

1313
/bindings/c/generated
1414
/bindings/c/**.xcframework
15-
/bindings/**/.DS_Store
15+
/bindings/**/.DS_Store

Cargo.lock

Lines changed: 9 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bottomless/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ anyhow = "1.0.66"
1313
async-compression = { version = "0.4.4", features = ["tokio", "gzip", "zstd"] }
1414
aws-config = { version = "1" }
1515
aws-sdk-s3 = { version = "1" }
16+
aws-smithy-types = { version = "1" }
1617
bytes = "1"
1718
libsql-sys = { path = "../libsql-sys" }
1819
libsql_replication = { path = "../libsql-replication" }

bottomless/src/replicator.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use aws_sdk_s3::operation::list_objects::builders::ListObjectsFluentBuilder;
1515
use aws_sdk_s3::operation::list_objects::ListObjectsOutput;
1616
use aws_sdk_s3::primitives::ByteStream;
1717
use aws_sdk_s3::{Client, Config};
18+
use aws_smithy_types::timeout::TimeoutConfig;
1819
use bytes::{Buf, Bytes};
1920
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
2021
use libsql_replication::injector::Injector as _;
@@ -121,6 +122,12 @@ pub struct Options {
121122
pub s3_max_parallelism: usize,
122123
/// Max number of retries for S3 operations
123124
pub s3_max_retries: u32,
125+
/// Timeout for reading the first byte of an S3 response (seconds)
126+
pub s3_read_timeout_secs: u64,
127+
/// Timeout for establishing a TCP connection to S3 (seconds)
128+
pub s3_connect_timeout_secs: u64,
129+
/// Timeout for a single S3 operation attempt, including retries (seconds)
130+
pub s3_operation_attempt_timeout_secs: u64,
124131
/// Skip snapshot upload per checkpoint.
125132
pub skip_snapshot: bool,
126133
/// Skip uploading snapshots on shutdown
@@ -145,6 +152,11 @@ impl Options {
145152
"LIBSQL_BOTTOMLESS_AWS_SECRET_ACCESS_KEY was not set"
146153
))?;
147154
let session_token: Option<String> = self.session_token.clone();
155+
let timeout_config = TimeoutConfig::builder()
156+
.read_timeout(Duration::from_secs(self.s3_read_timeout_secs))
157+
.connect_timeout(Duration::from_secs(self.s3_connect_timeout_secs))
158+
.operation_attempt_timeout(Duration::from_secs(self.s3_operation_attempt_timeout_secs))
159+
.build();
148160
let conf = loader
149161
.behavior_version(BehaviorVersion::latest())
150162
.region(Region::new(region))
@@ -159,6 +171,7 @@ impl Options {
159171
aws_sdk_s3::config::retry::RetryConfig::standard()
160172
.with_max_attempts(self.s3_max_retries),
161173
)
174+
.timeout_config(timeout_config)
162175
.build();
163176

164177
let s3_config = aws_sdk_s3::config::Builder::from(&conf)
@@ -233,6 +246,12 @@ impl Options {
233246
),
234247
};
235248
let s3_max_retries = env_var_or("LIBSQL_BOTTOMLESS_S3_MAX_RETRIES", 10).parse::<u32>()?;
249+
let s3_read_timeout_secs =
250+
env_var_or("LIBSQL_BOTTOMLESS_S3_READ_TIMEOUT_SECS", 5).parse::<u64>()?;
251+
let s3_connect_timeout_secs =
252+
env_var_or("LIBSQL_BOTTOMLESS_S3_CONNECT_TIMEOUT_SECS", 5).parse::<u64>()?;
253+
let s3_operation_attempt_timeout_secs =
254+
env_var_or("LIBSQL_BOTTOMLESS_S3_OPERATION_ATTEMPT_TIMEOUT_SECS", 10).parse::<u64>()?;
236255
let cipher = match encryption_cipher {
237256
Some(cipher) => Cipher::from_str(&cipher)?,
238257
None => Cipher::default(),
@@ -261,6 +280,9 @@ impl Options {
261280
region,
262281
bucket_name,
263282
s3_max_retries,
283+
s3_read_timeout_secs,
284+
s3_connect_timeout_secs,
285+
s3_operation_attempt_timeout_secs,
264286
skip_snapshot,
265287
skip_shutdown_upload,
266288
})

libsql-server/src/namespace/meta_store.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ pub async fn metastore_connection_maker(
129129
max_batch_interval: config.backup_interval,
130130
s3_max_parallelism: 32,
131131
s3_max_retries: 10,
132+
s3_read_timeout_secs: 5,
133+
s3_connect_timeout_secs: 5,
134+
s3_operation_attempt_timeout_secs: 10,
132135
skip_snapshot: false,
133136
skip_shutdown_upload: false,
134137
};

libsql-server/tests/bottomless/basic_restore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ async fn test_basic_restore() {
3636
.expect("Failed to cleanup dbs dir");
3737

3838
// Phase 3: Start sqld - should restore from minio
39-
let endpoint2 = sqld.http_endpoint();
4039
sqld.start(data_dir.path())
4140
.await
4241
.expect("Failed to restart sqld");
42+
let endpoint2 = sqld.http_endpoint();
4343
sqld.wait_for_ready(Duration::from_secs(60))
4444
.await
4545
.expect("sqld did not become ready after restore");

0 commit comments

Comments
 (0)