feat(core): add configurable pool import timeout for large pools - #1083
feat(core): add configurable pool import timeout for large pools#1083azgms wants to merge 2 commits into
Conversation
The timeout_grpc() function capped all operation timeouts at 59s via .min(Duration::from_secs(59)). This silently clamped operations whose minimum timeout intentionally exceeded that cap: - nvme_reconnect: configured at 62s, was capped to 59s - ImportPool: computed as pool(20s) * 3 = 60s, was capped to 59s The cap now only applies when the operation's minimum timeout is <= 59s. Operations that explicitly declare a higher minimum are no longer clamped. Adds unit tests for timeout_grpc() covering the cap behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When an io-engine pod restarts, agent-core re-imports pools via the ImportPool gRPC call. On large pools (e.g. 196 TiB with many lvols), the SPDK blobstore metadata scan can exceed the default 60s timeout, causing an infinite timeout-retry loop that prevents pool recovery. Add a --pool-import-timeout CLI arg (also configurable via POOL_IMPORT_TIMEOUT env var) that sets an explicit timeout for pool import operations. When not specified, the existing default behavior (pool * 3 = 60s) is preserved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Hey, thanks for the change. We already have a fix for the long create call here which defaults to 15 minutes. So we allow timeout but then async we check if the pool is created. Perhaps we need a similar one to the import as well? What do you think? |
@tiagolobocastro as we were discussing, how about a new state + refresh? |
|
@azgms , I agree with mimicking behaviour of |
Summary
When an io-engine pod restarts, agent-core re-imports disk pools via ImportPool gRPC. On large pools (e.g. ~200 TiB with many lvols), the SPDK blobstore metadata scan can exceed 60s, hitting the hardcoded timeout cap and causing an infinite timeout-retry loop.
This PR:
timeout_grpc()so operations whose minimum timeout intentionally exceeds 59s are no longer silently clamped (also fixesnvme_reconnectat 62s being capped to 59s)--pool-import-timeoutCLI arg (env:POOL_IMPORT_TIMEOUT) to set an explicit timeout for pool import operationsWhen
--pool-import-timeoutis not specified, behavior is unchanged.Motivation
We run a ~200 TiB Mayastor disk pool across 2 storage nodes. After an io-engine crash, the pool import consistently exceeded the 59s gRPC timeout. Agent-core retried every 10s, flooding the freshly restarted io-engine with import + nexus + replica requests, preventing the import from ever completing. The pool was stuck in Unknown state indefinitely.
Architectural Safety
The 59s cap change is conservative
The cap logic changes from unconditional
.min(59s)to conditional: only operations whoseop_timeout <= 59sare still capped. This affects exactly two operations today:pool * 3calculationAll other operations (replica, nexus, pool create/destroy, snapshots) have
op_timeout <= 30sand remain capped at 59s exactly as before.The 60s tonic channel timeout is NOT affected
Pool import flows through
GrpcContext(client.rs:56-63), which creates its owntonic::transport::Endpointwith.timeout(timeout)set to the result oftimeout_grpc(). The separate 60s hardcoded channel timeout inContext::endpoint()(line 145) is only used by the rest-server/csi-to-core-agent path and is not involved.Node operation serialization
Node operations are serialized via
Arc<Mutex>per node (GrpcClientLocked). A longer pool import timeout means other operations on that node queue behind it longer. This is acceptable: during pool import, the pool is in Unknown state, so nexus/replica operations targeting that pool would fail regardless. Letting the import complete is strictly better than the current behavior of timing out and retrying in a 10s loop indefinitely.No impact on reconciler behavior
The pool reconciler continues to retry imports every reconciliation cycle (default 10s). The only difference is that each attempt now has enough time to succeed on large pools, breaking the infinite timeout-retry loop.
Changes
grpc/src/context.rspool_import(), add 5 unit testsstor-port/src/transport_api/mod.rspool_importfield, accessor, builderagents/src/bin/core/main.rs--pool-import-timeoutCLI argagents/src/bin/core/node/mod.rsagents/src/bin/core/node/service.rsRequestMinTimeoutagents/src/bin/core/node/wrapper.rsNodeCommsTimeout::new()call sitesagents/.../snap_rebuild.rsNodeCommsTimeout::new()call siteBackward Compatibility
--pool-import-timeoutis not setnvme_reconnect(62s) is no longer capped to 59s, which was always a bug--no-min-timeoutscontinues to bypass all operation-specific timeoutsTest plan
timeout_grpc()covering cap behavior (5 tests)cargo check -p agents --bin corepasses--pool-import-timeout=300s, verify import uses 300s