标注SpacetimeDB超时阶段

为SpacetimeDB客户端超时错误记录阶段信息

同步更新后端超时错误映射

避免方洞背景图导入失败误报
This commit is contained in:
2026-06-25 20:10:18 +08:00
parent 6277a823ba
commit 9516132e94
9 changed files with 50 additions and 35 deletions
@@ -271,7 +271,7 @@ pub(crate) fn should_skip_asset_operation_billing_for_connectivity(
error: &SpacetimeClientError,
) -> bool {
match error {
SpacetimeClientError::ConnectDropped | SpacetimeClientError::Timeout => true,
SpacetimeClientError::ConnectDropped | SpacetimeClientError::Timeout(_) => true,
SpacetimeClientError::Build(message)
| SpacetimeClientError::Procedure(message)
| SpacetimeClientError::Runtime(message) => {
+10 -3
View File
@@ -935,12 +935,17 @@ fn map_big_fish_client_error(error: SpacetimeClientError) -> AppError {
StatusCode::BAD_REQUEST
}
SpacetimeClientError::Runtime(_) => StatusCode::BAD_REQUEST,
SpacetimeClientError::Timeout => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::Timeout(_) => StatusCode::GATEWAY_TIMEOUT,
_ => StatusCode::BAD_GATEWAY,
};
let message = match &error {
SpacetimeClientError::Timeout => "SpacetimeDB 会话读取超时,请稍后重试。".to_string(),
SpacetimeClientError::Timeout(stage) => {
format!(
"SpacetimeDB 会话读取超时({}),请稍后重试。",
stage.as_str()
)
}
SpacetimeClientError::ConnectDropped => {
"SpacetimeDB 会话连接已断开,请稍后重试。".to_string()
}
@@ -983,6 +988,8 @@ fn current_timestamp_micros_to_string(value: i64) -> String {
#[cfg(test)]
mod tests {
use spacetime_client::SpacetimeClientStage;
use super::*;
#[test]
@@ -1001,7 +1008,7 @@ mod tests {
#[test]
fn big_fish_gallery_keeps_timeout_errors_visible() {
assert!(!should_soft_fallback_big_fish_gallery(
&SpacetimeClientError::Timeout
&SpacetimeClientError::Timeout(SpacetimeClientStage::ProcedureResult)
));
}
}
@@ -1,4 +1,5 @@
use super::*;
use spacetime_client::SpacetimeClientStage;
pub(super) fn map_big_fish_session_response(
session: BigFishSessionRecord,
@@ -237,7 +238,7 @@ pub(super) async fn load_big_fish_session_with_retry(
.await
{
Ok(session) => return Ok(session),
Err(error @ SpacetimeClientError::Timeout)
Err(error @ SpacetimeClientError::Timeout(_))
| Err(error @ SpacetimeClientError::ConnectDropped) => {
last_retryable_error = Some(error);
if attempt == 0 {
@@ -249,7 +250,11 @@ pub(super) async fn load_big_fish_session_with_retry(
}
}
Err(last_retryable_error.unwrap_or(SpacetimeClientError::Timeout))
Err(
last_retryable_error.unwrap_or(SpacetimeClientError::Timeout(
SpacetimeClientStage::ProcedureResult,
)),
)
}
pub(super) fn map_record_anchor_pack_to_domain(
@@ -133,7 +133,7 @@ fn map_public_work_client_error(error: SpacetimeClientError) -> AppError {
{
StatusCode::NOT_FOUND
}
SpacetimeClientError::Timeout => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::Timeout(_) => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::ConnectDropped => StatusCode::SERVICE_UNAVAILABLE,
_ => StatusCode::BAD_GATEWAY,
};
@@ -382,7 +382,7 @@ pub(super) fn puzzle_bad_request(
pub(super) fn map_puzzle_client_error(error: SpacetimeClientError) -> AppError {
let status = match &error {
SpacetimeClientError::ConnectDropped => StatusCode::SERVICE_UNAVAILABLE,
SpacetimeClientError::Timeout => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::Timeout(_) => StatusCode::GATEWAY_TIMEOUT,
error if should_skip_asset_operation_billing_for_connectivity(error) => {
StatusCode::SERVICE_UNAVAILABLE
}
@@ -450,7 +450,7 @@ pub(super) fn map_puzzle_compile_error(error: SpacetimeClientError) -> AppError
StatusCode::SERVICE_UNAVAILABLE
} else if matches!(
error,
SpacetimeClientError::ConnectDropped | SpacetimeClientError::Timeout
SpacetimeClientError::ConnectDropped | SpacetimeClientError::Timeout(_)
) || should_skip_asset_operation_billing_for_connectivity(&error)
{
StatusCode::SERVICE_UNAVAILABLE
@@ -485,7 +485,7 @@ pub(super) fn map_puzzle_compile_error(error: SpacetimeClientError) -> AppError
StatusCode::BAD_GATEWAY
}
SpacetimeClientError::ConnectDropped => StatusCode::SERVICE_UNAVAILABLE,
SpacetimeClientError::Timeout => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::Timeout(_) => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::Runtime(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::BAD_GATEWAY,
}
+2 -1
View File
@@ -1604,6 +1604,7 @@ fn is_missing_creation_entry_config_procedure(error: &SpacetimeClientError) -> b
#[cfg(test)]
mod tests {
use module_ai::{AiTaskKind, generate_ai_task_id};
use spacetime_client::SpacetimeClientStage;
use super::*;
@@ -1618,7 +1619,7 @@ mod tests {
&SpacetimeClientError::Procedure("No such procedure".to_string()),
));
assert!(!is_missing_creation_entry_config_procedure(
&SpacetimeClientError::Timeout,
&SpacetimeClientError::Timeout(SpacetimeClientStage::ProcedureResult),
));
}
@@ -1455,7 +1455,7 @@ fn map_spacetime_error(error: SpacetimeClientError) -> AppError {
{
StatusCode::FORBIDDEN
}
SpacetimeClientError::Timeout => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::Timeout(_) => StatusCode::GATEWAY_TIMEOUT,
SpacetimeClientError::ConnectDropped => StatusCode::SERVICE_UNAVAILABLE,
_ => StatusCode::BAD_GATEWAY,
};
+11 -9
View File
@@ -360,7 +360,7 @@ pub enum SpacetimeClientError {
ConnectDropped,
Procedure(String),
Runtime(String),
Timeout,
Timeout(SpacetimeClientStage),
}
const DEFAULT_PROCEDURE_TIMEOUT: Duration = Duration::from_secs(30);
@@ -711,7 +711,7 @@ impl SpacetimeClient {
.map_err(|_| {
SpacetimeStageError::new(
SpacetimeClientStage::PoolAcquire,
SpacetimeClientError::Timeout,
SpacetimeClientError::Timeout(SpacetimeClientStage::PoolAcquire),
)
})?
.map_err(|error| {
@@ -804,7 +804,7 @@ impl SpacetimeClient {
.map_err(|_| {
SpacetimeStageError::new(
SpacetimeClientStage::ConnectBuild,
SpacetimeClientError::Timeout,
SpacetimeClientError::Timeout(SpacetimeClientStage::ConnectBuild),
)
})?
.map_err(|error| {
@@ -821,7 +821,7 @@ impl SpacetimeClient {
.map_err(|_| {
SpacetimeStageError::new(
SpacetimeClientStage::ConnectHandshake,
SpacetimeClientError::Timeout,
SpacetimeClientError::Timeout(SpacetimeClientStage::ConnectHandshake),
)
})?
.map_err(|_| {
@@ -945,7 +945,7 @@ impl SpacetimeClient {
.map_err(|_| {
SpacetimeStageError::new(
SpacetimeClientStage::ReadModelSubscribe,
SpacetimeClientError::Timeout,
SpacetimeClientError::Timeout(SpacetimeClientStage::ReadModelSubscribe),
)
})?
.map_err(|_| {
@@ -970,7 +970,7 @@ impl SpacetimeClient {
// 超时后必须统一归还租约;若连接已先一步断开则回传断线,否则标记坏连接并回传超时。
fn resolve_timeout_error(
connection: Option<&PooledConnection>,
_stage: SpacetimeClientStage,
stage: SpacetimeClientStage,
) -> SpacetimeClientError {
if let Some(connection) = connection {
if connection.is_broken() {
@@ -979,7 +979,7 @@ impl SpacetimeClient {
connection.mark_broken();
}
SpacetimeClientError::Timeout
SpacetimeClientError::Timeout(stage)
}
}
@@ -1127,7 +1127,9 @@ impl fmt::Display for SpacetimeClientError {
f.write_str(message)
}
Self::ConnectDropped => f.write_str("SpacetimeDB 连接在返回结果前已断开"),
Self::Timeout => f.write_str("SpacetimeDB procedure 调用超时"),
Self::Timeout(stage) => {
f.write_str(&format!("SpacetimeDB {} 调用超时", stage.as_str()))
}
}
}
}
@@ -1241,6 +1243,6 @@ mod tests {
Err(error) => error,
};
assert_eq!(error.stage, SpacetimeClientStage::PoolAcquire);
assert!(matches!(error.error, SpacetimeClientError::Timeout));
assert!(matches!(error.error, SpacetimeClientError::Timeout(_)));
}
}
@@ -9,13 +9,7 @@ import {
Send,
Trash2,
} from 'lucide-react';
import {
type ChangeEvent,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { type ChangeEvent, useEffect, useMemo, useRef, useState } from 'react';
import type { SquareHoleResultDraft } from '../../../packages/shared/src/contracts/squareHoleAgent';
import type {
@@ -24,6 +18,11 @@ import type {
SquareHoleShapeOption,
SquareHoleWorkProfile,
} from '../../../packages/shared/src/contracts/squareHoleWorks';
import {
canUseNativeHostCapability,
type HostFileImportImageResult,
importHostImageFile,
} from '../../services/host-bridge/hostBridge';
import {
publishSquareHoleWork,
regenerateSquareHoleWorkImage,
@@ -32,14 +31,9 @@ import {
type SquareHoleImageAssetKind,
updateSquareHoleWork,
} from '../../services/square-hole-works';
import {
canUseNativeHostCapability,
type HostFileImportImageResult,
importHostImageFile,
} from '../../services/host-bridge/hostBridge';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformBackActionButton } from '../common/PlatformBackActionButton';
import { PlatformAssetPickerGrid } from '../common/PlatformAssetPickerCard';
import { PlatformBackActionButton } from '../common/PlatformBackActionButton';
import { PlatformFieldLabel } from '../common/PlatformFieldLabel';
import { PlatformIconButton } from '../common/PlatformIconButton';
import { PlatformMediaFrame } from '../common/PlatformMediaFrame';
@@ -47,11 +41,11 @@ import { PlatformPillBadge } from '../common/PlatformPillBadge';
import { PlatformStatGrid } from '../common/PlatformStatGrid';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import { PlatformSubpanel } from '../common/PlatformSubpanel';
import { PlatformToolModalShell } from '../common/PlatformToolModalShell';
import {
PlatformSelectField,
PlatformTextField,
} from '../common/PlatformTextField';
import { PlatformToolModalShell } from '../common/PlatformToolModalShell';
type SquareHoleResultViewProps = {
profile: SquareHoleWorkProfile;
@@ -792,6 +786,9 @@ export function SquareHoleResultView({
setEditState((current) => applyImageSlotSrc(current, slot, dataUrl));
setLocalError(null);
} catch (caughtError) {
if (slot.kind === 'background') {
return;
}
setLocalError(
caughtError instanceof Error ? caughtError.message : '图片读取失败。',
);
@@ -823,6 +820,9 @@ export function SquareHoleResultView({
);
setLocalError(null);
} catch (caughtError) {
if (slot.kind === 'background') {
return;
}
setLocalError(
caughtError instanceof Error ? caughtError.message : '图片读取失败。',
);