From 1934cddd66cde9e07fec5b4cba01fe25247ad467 Mon Sep 17 00:00:00 2001 From: Zhengchao An Date: Tue, 4 Aug 2026 11:46:53 +0800 Subject: [PATCH] fix(ecstore): skip walkdir total timeout for listing operations (#5684) Large buckets with millions of objects can take longer than the default 5-second walkdir timeout to produce the first page of listing results. This causes timeouts in the web UI and mc CLI when opening or scanning such buckets. Skip the walkdir total timeout for S3 ListObjects operations when no explicit walkdir_timeout is configured. The stall timeout (5s with no forward progress) still protects against drives that stop responding. This matches the scanner's existing behavior for the same reason. Fixes #5647 --- crates/ecstore/src/store/list_objects.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/ecstore/src/store/list_objects.rs b/crates/ecstore/src/store/list_objects.rs index c8b9ecbbb..4d7eefa26 100644 --- a/crates/ecstore/src/store/list_objects.rs +++ b/crates/ecstore/src/store/list_objects.rs @@ -4333,7 +4333,7 @@ impl ECStore { filter_prefix: Some(filter_prefix.clone()), forward_to: opts.marker.clone(), per_disk_limit: bounded_usize_to_i32(opts.limit), - skip_total_timeout: false, + skip_total_timeout: opts.walkdir_timeout.is_none(), walkdir_timeout: opts.walkdir_timeout, walkdir_stall_timeout: opts.walkdir_stall_timeout, }, @@ -4356,6 +4356,12 @@ impl ECStore { forward_to: opts.marker.clone(), min_disks: raw_min_disks, per_disk_limit: bounded_usize_to_i32(opts.limit), + // Skip the total walkdir timeout for listing operations. + // Large buckets (millions of objects) can take longer than + // the default 5s walkdir timeout to produce the first page + // of results. The stall timeout still protects against + // drives that stop making forward progress. + skip_walkdir_total_timeout: opts.walkdir_timeout.is_none(), walkdir_timeout: opts.walkdir_timeout, walkdir_stall_timeout: opts.walkdir_stall_timeout, agreed: Some(Box::new(move |entry: MetaCacheEntry| { @@ -5554,7 +5560,7 @@ impl Sets { filter_prefix: Some(filter_prefix.clone()), forward_to: opts.marker.clone(), per_disk_limit: bounded_usize_to_i32(opts.limit), - skip_total_timeout: false, + skip_total_timeout: opts.walkdir_timeout.is_none(), walkdir_timeout: opts.walkdir_timeout, walkdir_stall_timeout: opts.walkdir_stall_timeout, }, @@ -5577,6 +5583,12 @@ impl Sets { forward_to: opts.marker.clone(), min_disks: raw_min_disks, per_disk_limit: bounded_usize_to_i32(opts.limit), + // Skip the total walkdir timeout for listing operations. + // Large buckets (millions of objects) can take longer than + // the default 5s walkdir timeout to produce the first page + // of results. The stall timeout still protects against + // drives that stop making forward progress. + skip_walkdir_total_timeout: opts.walkdir_timeout.is_none(), walkdir_timeout: opts.walkdir_timeout, walkdir_stall_timeout: opts.walkdir_stall_timeout, agreed: Some(Box::new(move |entry: MetaCacheEntry| {