From 410607c48079ed811165453b87d442b1e6651548 Mon Sep 17 00:00:00 2001 From: Maurus Decimus <11444311+mdecimus@users.noreply.github.com> Date: Thu, 7 May 2026 15:35:54 +0200 Subject: [PATCH] Fix Bootstrap: Timeout after 30 seconds when probing the data store --- CHANGELOG.md | 1 + crates/common/Cargo.toml | 2 +- crates/jmap/src/registry/mapping/bootstrap.rs | 36 +++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2751e078..439513a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If - Patching nested objects with `null` values fails. - SQL directory: Return `Failed` instead of `Error` when the query returns no results. - Network: Attempt binding to IPv4 when binding to IPv6 fails with `EAFNOSUPPORT` error. +- Bootstrap: Timeout after 30 seconds when probing the data store. ## [0.16.4] - 2026-05-05 diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index ac4b5b21..35a75875 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -18,7 +18,7 @@ imap_proto = { path = "../imap-proto" } sieve-rs = { version = "0.7", features = ["rkyv", "serde"] } mail-parser = { version = "0.11", features = ["full_encoding"] } mail-builder = { version = "0.4" } -mail-auth = { version = "0.9" } +mail-auth = { version = "0.9", features = ["generate"] } smtp-proto = { version = "0.2", features = ["rkyv"] } dns-update = { version = "0.2.1" } calcard = { version = "0.3", features = ["rkyv"] } diff --git a/crates/jmap/src/registry/mapping/bootstrap.rs b/crates/jmap/src/registry/mapping/bootstrap.rs index 3ce2be68..c00a4244 100644 --- a/crates/jmap/src/registry/mapping/bootstrap.rs +++ b/crates/jmap/src/registry/mapping/bootstrap.rs @@ -32,6 +32,7 @@ use registry::{ }, types::{ObjectImpl, list::List, map::Map}, }; +use std::time::Duration; use store::{ RegistryStore, SUBSPACE_PROPERTY, Store, registry::write::{RegistryWrite, RegistryWriteResult}, @@ -167,15 +168,13 @@ pub(crate) async fn bootstrap_set( } // Make sure this is blank deployment - match store - .get_value::(AnyKey { - subspace: SUBSPACE_PROPERTY, - key: vec![0u8], - }) - .await - { - Ok(None) => {} - Ok(Some(DATABASE_SCHEMA_VERSION)) => { + let probe = store.get_value::(AnyKey { + subspace: SUBSPACE_PROPERTY, + key: vec![0u8], + }); + match tokio::time::timeout(Duration::from_secs(30), probe).await { + Ok(Ok(None)) => {} + Ok(Ok(Some(DATABASE_SCHEMA_VERSION))) => { set.response.not_updated.append( id, SetError::invalid_properties() @@ -184,7 +183,7 @@ pub(crate) async fn bootstrap_set( ); break; } - Ok(Some(_)) => { + Ok(Ok(Some(_))) => { set.response.not_updated.append( id, SetError::invalid_properties() @@ -197,7 +196,7 @@ pub(crate) async fn bootstrap_set( ); break; } - Err(err) => { + Ok(Err(err)) => { trc::error!(err.caused_by(trc::location!())); set.response.not_updated.append( id, @@ -209,6 +208,21 @@ pub(crate) async fn bootstrap_set( ); break; } + Err(_elapsed) => { + set.response.not_updated.append( + id, + SetError::invalid_properties() + .with_property(Property::DataStore) + .with_description(concat!( + "Timed out probing the data store after 30 seconds. ", + "Check that the backend is reachable: for FoundationDB verify ", + "the cluster file points at reachable coordinators, for SQL ", + "verify the host and credentials, and for S3 verify the endpoint ", + "and bucket. See the server logs for details." + )), + ); + break; + } }; // Validate stores and registry