diff --git a/libs/utils/src/http/error.rs b/libs/utils/src/http/error.rs index 08182aea07..4efe1ac953 100644 --- a/libs/utils/src/http/error.rs +++ b/libs/utils/src/http/error.rs @@ -1,8 +1,9 @@ use hyper::{header, Body, Response, StatusCode}; use serde::{Deserialize, Serialize}; +use std::borrow::Cow; use std::error::Error as StdError; use thiserror::Error; -use tracing::error; +use tracing::{error, info}; #[derive(Debug, Error)] pub enum ApiError { @@ -25,7 +26,7 @@ pub enum ApiError { PreconditionFailed(Box), #[error("Resource temporarily unavailable: {0}")] - ResourceUnavailable(String), + ResourceUnavailable(Cow<'static, str>), #[error("Shutting down")] ShuttingDown, @@ -115,10 +116,11 @@ pub async fn route_error_handler(err: routerify::RouteError) -> Response { pub fn api_error_handler(api_error: ApiError) -> Response { // Print a stack trace for Internal Server errors - if let ApiError::InternalServerError(_) = api_error { - error!("Error processing HTTP request: {api_error:?}"); - } else { - error!("Error processing HTTP request: {api_error:#}"); + + match api_error { + ApiError::ResourceUnavailable(_) => info!("Error processing HTTP request: {api_error:#}"), + ApiError::InternalServerError(_) => error!("Error processing HTTP request: {api_error:?}"), + _ => error!("Error processing HTTP request: {api_error:#}"), } api_error.into_response() diff --git a/pageserver/src/http/routes.rs b/pageserver/src/http/routes.rs index f09e09c5a0..b8cb44c732 100644 --- a/pageserver/src/http/routes.rs +++ b/pageserver/src/http/routes.rs @@ -133,7 +133,7 @@ impl From for ApiError { ApiError::InternalServerError(anyhow::anyhow!("request was cancelled")) } PageReconstructError::AncestorStopping(_) => { - ApiError::ResourceUnavailable(format!("{pre}")) + ApiError::ResourceUnavailable(format!("{pre}").into()) } PageReconstructError::WalRedo(pre) => { ApiError::InternalServerError(anyhow::Error::new(pre)) @@ -146,7 +146,7 @@ impl From for ApiError { fn from(tmie: TenantMapInsertError) -> ApiError { match tmie { TenantMapInsertError::StillInitializing | TenantMapInsertError::ShuttingDown => { - ApiError::ResourceUnavailable(format!("{tmie}")) + ApiError::ResourceUnavailable(format!("{tmie}").into()) } TenantMapInsertError::TenantAlreadyExists(id, state) => { ApiError::Conflict(format!("tenant {id} already exists, state: {state:?}")) @@ -636,7 +636,7 @@ async fn tenant_list_handler( .instrument(info_span!("tenant_list")) .await .map_err(|_| { - ApiError::ResourceUnavailable("Tenant map is initializing or shutting down".to_string()) + ApiError::ResourceUnavailable("Tenant map is initializing or shutting down".into()) })? .iter() .map(|(id, state)| TenantInfo { diff --git a/test_runner/regress/test_duplicate_layers.py b/test_runner/regress/test_duplicate_layers.py index 62761e608c..ec5a2f7473 100644 --- a/test_runner/regress/test_duplicate_layers.py +++ b/test_runner/regress/test_duplicate_layers.py @@ -3,7 +3,10 @@ import time import pytest from fixtures.log_helper import log from fixtures.neon_fixtures import NeonEnvBuilder, PgBin, wait_for_last_flush_lsn -from fixtures.pageserver.utils import wait_for_upload_queue_empty +from fixtures.pageserver.utils import ( + wait_for_upload_queue_empty, + wait_until_tenant_active, +) from fixtures.remote_storage import LocalFsStorage, RemoteStorageKind from requests.exceptions import ConnectionError @@ -113,6 +116,8 @@ def test_actually_duplicated_l1(neon_env_builder: NeonEnvBuilder, pg_bin: PgBin) time.sleep(1) env.pageserver.start() + wait_until_tenant_active(pageserver_http, tenant_id) + message = f".*duplicated L1 layer layer={l1_found.name}" env.pageserver.allowed_errors.append(message)