fix(临时存储): RustFS 上传失败改为直接失败,不再静默回落 local 指针
多实例/容器化部署下 local 指针只有写入它的实例能读(跨节点读直接报错、容器重建即丢), 此前上传失败静默降级会把跨节点不可读的脏指针落库,故障延后到其它节点的合并/组装才爆。 现改为在写失败点抛 BusinessException(中文原因透传调用方),并新增 fallback-to-local-on-error 开关(默认 false)供单机部署回退旧行为; 跨实例读 local 指针的报错改中文并带 objectKey;超限回落策略不变。
This commit is contained in:
+27
-3
@@ -1,6 +1,7 @@
|
||||
package com.nanri.aiimage.modules.task.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.nanri.aiimage.common.exception.BusinessException;
|
||||
import com.nanri.aiimage.config.InstanceMetadata;
|
||||
import com.nanri.aiimage.config.StorageProperties;
|
||||
import com.nanri.aiimage.config.TransientStorageProperties;
|
||||
@@ -275,16 +276,39 @@ class TransientPayloadStorageServiceTest {
|
||||
assertThrows(IllegalStateException.class, () -> service.resolvePayload(pointer, "read failed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void uploadFailureFailsFastByDefaultWithoutLocalPointer() {
|
||||
// 默认(fallbackToLocalOnError=false):上传失败直接抛业务异常,不写本地文件、
|
||||
// 不置 fallback 标记、不记降级指标——避免产生跨实例不可读的 local 脏指针。
|
||||
RustfsObjectStorageService rustfs = mock(RustfsObjectStorageService.class);
|
||||
when(rustfs.isConfigured()).thenReturn(true);
|
||||
when(rustfs.uploadBytes(anyString(), any(byte[].class), anyBoolean()))
|
||||
.thenThrow(new IllegalStateException("rustfs upload down"));
|
||||
TransientPayloadStorageService service = newService(rustfs, propertiesWithLimit(1024, 4096, true));
|
||||
|
||||
BusinessException ex = assertThrows(BusinessException.class,
|
||||
() -> service.storeChunkPayload("TEST", 9L, "scope", 1, "{\"a\":1}"));
|
||||
|
||||
assertTrue(ex.getMessage().contains("临时存储(RustFS)不可用"));
|
||||
assertTrue(ex.getMessage().contains("objectKey=task-chunk/test/9/scope/chunk-1.json"));
|
||||
assertFalse(service.wasLastStoreLocalFallback());
|
||||
verify(rustfs, never()).recordLocalFallback();
|
||||
assertFalse(java.nio.file.Files.exists(tempDir.resolve("transient-payload")),
|
||||
"失败时不应落任何本地临时文件");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_task_064_payload_compression_dependency_failure_releases_resources() {
|
||||
// 依赖失败:上传失败回落本地且标记 fallback;随后上传恢复重新走 rustfs,
|
||||
// 失败期间无残留文件泄漏(本地文件可被清理),错误路径不产生重复对象。
|
||||
// 依赖失败:开关显式打开(单机降级模式)时上传失败回落本地且标记 fallback;
|
||||
// 随后上传恢复重新走 rustfs,失败期间无残留文件泄漏(本地文件可被清理),错误路径不产生重复对象。
|
||||
RustfsObjectStorageService rustfs = mock(RustfsObjectStorageService.class);
|
||||
when(rustfs.isConfigured()).thenReturn(true);
|
||||
when(rustfs.uploadBytes(anyString(), any(byte[].class), anyBoolean()))
|
||||
.thenThrow(new IllegalStateException("rustfs upload down"))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
TransientPayloadStorageService service = newService(rustfs, propertiesWithLimit(1024, 4096, true));
|
||||
TransientStorageProperties properties = propertiesWithLimit(1024, 4096, true);
|
||||
properties.setFallbackToLocalOnError(true);
|
||||
TransientPayloadStorageService service = newService(rustfs, properties);
|
||||
|
||||
String fallbackPointer = service.storeParsedPayloadFast("TEST", 1L, "scope", "{\"a\":1}", false);
|
||||
assertTrue(fallbackPointer.startsWith("local:"));
|
||||
|
||||
Reference in New Issue
Block a user