Revert "refactor(storage): 简化存储适配器配置逻辑并移除降级机制"

This reverts commit 95c82cfcf2.
This commit is contained in:
2026-02-05 22:29:52 +08:00
parent ee2482a55a
commit 1e71add551
8 changed files with 102 additions and 66 deletions

View File

@@ -25,6 +25,8 @@ import java.io.File;
) )
public class UploadStage extends AbstractPipelineStage<PhotoProcessContext> { public class UploadStage extends AbstractPipelineStage<PhotoProcessContext> {
private static final String DEFAULT_STORAGE = "assets-ext";
@Override @Override
public String getName() { public String getName() {
return "UploadStage"; return "UploadStage";
@@ -37,11 +39,17 @@ public class UploadStage extends AbstractPipelineStage<PhotoProcessContext> {
return StageResult.failed("没有可上传的文件"); return StageResult.failed("没有可上传的文件");
} }
IStorageAdapter adapter; IStorageAdapter adapter = context.getStorageAdapter();
try { boolean usingDefaultStorage = false;
adapter = StorageFactory.use();
} catch (Exception e) { if (adapter == null) {
return StageResult.failed("无法获取存储: " + e.getMessage(), e); log.debug("未配置存储适配器,使用默认存储: {}", DEFAULT_STORAGE);
try {
adapter = StorageFactory.use(DEFAULT_STORAGE);
usingDefaultStorage = true;
} catch (Exception e) {
return StageResult.failed("无法获取默认存储: " + e.getMessage(), e);
}
} }
try { try {
@@ -49,10 +57,32 @@ public class UploadStage extends AbstractPipelineStage<PhotoProcessContext> {
context.setResultUrl(uploadedUrl); context.setResultUrl(uploadedUrl);
log.info("文件上传成功: {}", uploadedUrl); log.info("文件上传成功: {}", uploadedUrl);
if (usingDefaultStorage) {
return StageResult.degraded("降级: 使用默认存储 " + DEFAULT_STORAGE);
}
return StageResult.success("已上传"); return StageResult.success("已上传");
} catch (Exception e) { } catch (Exception e) {
log.error("文件上传失败", e); log.error("文件上传失败", e);
if (!usingDefaultStorage) {
log.warn("尝试降级到默认存储");
try {
IStorageAdapter defaultAdapter = StorageFactory.use(DEFAULT_STORAGE);
String uploadedUrl = uploadFile(defaultAdapter, fileToUpload);
context.setResultUrl(uploadedUrl);
log.info("降级上传成功: {}", uploadedUrl);
return StageResult.degraded("降级: 使用默认存储 " + DEFAULT_STORAGE);
} catch (Exception fallbackEx) {
log.error("降级上传也失败", fallbackEx);
return StageResult.failed("上传失败(包括降级): " + fallbackEx.getMessage(), fallbackEx);
}
}
return StageResult.failed("上传失败: " + e.getMessage(), e); return StageResult.failed("上传失败: " + e.getMessage(), e);
} }
} }

View File

@@ -468,14 +468,12 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService {
// 上传到OSS // 上传到OSS
try (FileInputStream fis = new FileInputStream(qrcode)) { try (FileInputStream fis = new FileInputStream(qrcode)) {
String fileName = String.format("qrcode_%d.jpg", faceId); String fileName = String.format("qrcode_%d.jpg", faceId);
var storageAdapter = StorageFactory.use(); boolean exists = StorageFactory.use().isExists("puzzle", "wechat_qrcode", fileName);
boolean exists = storageAdapter.isExists("puzzle", "wechat_qrcode", fileName);
if (exists) { if (exists) {
String url = storageAdapter.getUrl("puzzle", "wechat_qrcode", fileName); log.debug("微信小程序二维码已存在, 不重复上传: faceId={}, url={}", faceId, StorageFactory.use().getUrl("puzzle", "wechat_qrcode", fileName));
log.debug("微信小程序二维码已存在, 不重复上传: faceId={}, url={}", faceId, url); return StorageFactory.use().getUrl("puzzle", "wechat_qrcode", fileName);
return url;
} }
return storageAdapter.uploadFile( return StorageFactory.use().uploadFile(
"image/jpeg", "image/jpeg",
fis, fis,
"puzzle", "puzzle",

View File

@@ -19,6 +19,7 @@ import com.ycwl.basic.pricing.enums.VoucherDiscountType;
import com.ycwl.basic.pricing.service.IVoucherService; import com.ycwl.basic.pricing.service.IVoucherService;
import com.ycwl.basic.storage.StorageFactory; import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.exceptions.StorageUnsupportedException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@@ -153,7 +154,14 @@ public class SourceRepository {
.build(); .build();
context.enableStage("image_sr"); context.enableStage("image_sr");
context.enableStage("image_enhance"); context.enableStage("image_enhance");
IStorageAdapter adapter = StorageFactory.use(); ScenicConfigManager configManager = scenicRepository.getScenicConfigManager(source.getScenicId());
IStorageAdapter adapter;
try {
adapter = StorageFactory.get(configManager.getString("store_type"));
adapter.loadConfig(configManager.getObject("store_config_json", Map.class));
} catch (StorageUnsupportedException ignored) {
adapter = StorageFactory.use("assets-ext");
}
context.setStorageAdapter(adapter); context.setStorageAdapter(adapter);
// 2. 设置结果URL回调 - 更新source记录 // 2. 设置结果URL回调 - 更新source记录

View File

@@ -51,6 +51,7 @@ import com.ycwl.basic.model.repository.TaskUpdateResult;
import com.ycwl.basic.storage.StorageFactory; import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl; import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.storage.enums.StorageType;
import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.WxMpUtil; import com.ycwl.basic.utils.WxMpUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -572,7 +573,13 @@ public class GoodsServiceImpl implements GoodsService {
if (configManager != null && configManager.getString("watermark_type") != null && !isBuy.isBuy()) { if (configManager != null && configManager.getString("watermark_type") != null && !isBuy.isBuy()) {
ImageWatermarkOperatorEnum type = ImageWatermarkOperatorEnum.getByCode(configManager.getString("watermark_type")); ImageWatermarkOperatorEnum type = ImageWatermarkOperatorEnum.getByCode(configManager.getString("watermark_type"));
if (type != null) { if (type != null) {
IStorageAdapter adapter = StorageFactory.use(); IStorageAdapter adapter;
if (configManager.getEnum("store_type", StorageType.class) != null) {
adapter = StorageFactory.get(configManager.getEnum("store_type", StorageType.class));
adapter.loadConfig(JacksonUtil.parseObject(configManager.getString("store_config_json"), Map.class));
} else {
adapter = StorageFactory.use("assets-ext");
}
List<SourceWatermarkEntity> watermarkEntityList = sourceMapper.listSourceWatermark(list.stream().map(SourceRespVO::getId).collect(Collectors.toList()), face.getId(), type.getType()); List<SourceWatermarkEntity> watermarkEntityList = sourceMapper.listSourceWatermark(list.stream().map(SourceRespVO::getId).collect(Collectors.toList()), face.getId(), type.getType());
// 边缘端处理:需要二维码和头像 URL // 边缘端处理:需要二维码和头像 URL

View File

@@ -13,6 +13,7 @@ import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
import com.ycwl.basic.repository.DeviceRepository; import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.SourceRepository; import com.ycwl.basic.repository.SourceRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.pc.SourceService; import com.ycwl.basic.service.pc.SourceService;
import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.task.VideoPieceGetter; import com.ycwl.basic.task.VideoPieceGetter;
@@ -46,6 +47,8 @@ public class SourceServiceImpl implements SourceService {
@Autowired @Autowired
private SourceRepository sourceRepository; private SourceRepository sourceRepository;
@Autowired @Autowired
private ScenicService scenicService;
@Autowired
private ScenicRepository scenicRepository; private ScenicRepository scenicRepository;
@Autowired @Autowired
private DeviceRepository deviceRepository; private DeviceRepository deviceRepository;
@@ -181,7 +184,7 @@ public class SourceServiceImpl implements SourceService {
throw new BaseException("该素材不存在"); throw new BaseException("该素材不存在");
} }
try { try {
IStorageAdapter adapter = StorageFactory.use(); IStorageAdapter adapter = scenicService.getScenicStorageAdapter(source.getScenicId());
String uploadedUrl = adapter.uploadFile("image/jpeg", file, PHOTO_PATH, id + "_q_.jpg"); String uploadedUrl = adapter.uploadFile("image/jpeg", file, PHOTO_PATH, id + "_q_.jpg");
SourceEntity sourceUpd = new SourceEntity(); SourceEntity sourceUpd = new SourceEntity();

View File

@@ -1103,7 +1103,25 @@ public class PrinterServiceImpl implements PrinterService {
* 从context中的scenicConfigManager获取配置 * 从context中的scenicConfigManager获取配置
*/ */
private void prepareStorageAdapter(PhotoProcessContext context) { private void prepareStorageAdapter(PhotoProcessContext context) {
context.setStorageAdapter(StorageFactory.use()); ScenicConfigManager scenicConfig = context.getScenicConfigManager();
if (scenicConfig == null) {
log.warn("scenicConfigManager未设置,将使用默认存储");
return;
}
try {
String storeType = scenicConfig.getString("store_type");
if (storeType != null) {
IStorageAdapter adapter = StorageFactory.get(storeType);
String storeConfigJson = scenicConfig.getString("store_config_json");
if (StringUtils.isNotBlank(storeConfigJson)) {
adapter.loadConfig(JacksonUtil.parseObject(storeConfigJson, Map.class));
}
context.setStorageAdapter(adapter);
}
} catch (Exception e) {
log.warn("准备存储适配器失败,将使用默认存储: {}", e.getMessage());
}
} }
@Override @Override

View File

@@ -601,7 +601,14 @@ public class TaskTaskServiceImpl implements TaskService {
if (worker == null) { if (worker == null) {
return null; return null;
} }
IStorageAdapter adapter = scenicService.getScenicStorageAdapter(task.getScenicId()); RenderWorkerConfigManager config = repository.getWorkerConfigManager(worker.getId());
IStorageAdapter adapter;
try {
adapter = StorageFactory.get(config.getString("store_type"));
adapter.loadConfig(config.getObject("store_config_json", Map.class));
} catch (Exception e) {
adapter = scenicService.getScenicStorageAdapter(task.getScenicId());
}
String hash = MD5.create().digestHex(task.getTaskParams() + task.getFaceId().toString()); String hash = MD5.create().digestHex(task.getTaskParams() + task.getFaceId().toString());
String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getTemplateId().toString() + "_" + hash + "_" + task.getScenicId() + ".mp4"); String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getTemplateId().toString() + "_" + hash + "_" + task.getScenicId() + ".mp4");
// 生成 // 生成

View File

@@ -34,9 +34,7 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME; import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
@@ -228,16 +226,6 @@ public class FaceCleaner {
public void cleanSourceOss() { public void cleanSourceOss() {
log.info("开始清理源视频素材文件"); log.info("开始清理源视频素材文件");
List<SourceRespVO> list = sourceMapper.list(new SourceReqQuery()); List<SourceRespVO> list = sourceMapper.list(new SourceReqQuery());
Map<Long, String> sourceImageUrlMap = new HashMap<>();
Map<Long, Long> sourceScenicIdMap = new HashMap<>();
list.forEach(item -> {
if (item.getId() != null && item.getScenicId() != null) {
sourceScenicIdMap.put(item.getId(), item.getScenicId());
}
if (item.getId() != null) {
sourceImageUrlMap.put(item.getId(), item.getUrl());
}
});
ArrayList<String> adapterIdentity = new ArrayList<>(); ArrayList<String> adapterIdentity = new ArrayList<>();
ScenicReqQuery query = new ScenicReqQuery(); ScenicReqQuery query = new ScenicReqQuery();
query.setPageSize(1000); query.setPageSize(1000);
@@ -272,45 +260,22 @@ public class FaceCleaner {
log.info("文件存在关系:{},未删除", fileObject); log.info("文件存在关系:{},未删除", fileObject);
} }
}); });
}); log.info("开始清理图片文件");
fileObjectList = adapter.listDir(StorageConstant.PHOTO_PATH);
log.info("开始清理图片文件"); fileObjectList.parallelStream().forEach(fileObject -> {
IStorageAdapter imageAdapter = StorageFactory.use(); if (fileObject.getModifyTime() != null) {
List<StorageFileObject> fileObjectList = imageAdapter.listDir(StorageConstant.PHOTO_PATH); // 如果是一天以内修改的,则跳过
fileObjectList.parallelStream().forEach(fileObject -> { if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) <= 1) {
if (fileObject.getModifyTime() != null) { return;
// 如果是一天以内修改的,则跳过 }
if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) <= 1) {
return;
} }
} if (list.parallelStream().filter(videoRespVO -> Objects.nonNull(videoRespVO.getUrl())).noneMatch(videoRespVO -> videoRespVO.getUrl().contains(fileObject.getName()))){
log.info("删除文件:{}", fileObject);
String name = fileObject.getName(); adapter.deleteFile(fileObject.getFullPath());
if (name == null) { } else {
return; log.info("文件存在关系:{},未删除", fileObject);
} }
int underscoreIndex = name.indexOf('_'); });
if (underscoreIndex <= 0) {
return;
}
Long sourceId;
try {
sourceId = Long.parseLong(name.substring(0, underscoreIndex));
} catch (NumberFormatException e) {
return;
}
Long scenicId = sourceScenicIdMap.get(sourceId);
if (scenicId == null || disableDeleteScenicIds.contains(scenicId.toString())) {
return;
}
String imageUrl = sourceImageUrlMap.get(sourceId);
if (imageUrl != null && imageUrl.contains(name)) {
log.info("文件存在关系:{},未删除", fileObject);
return;
}
log.info("删除文件:{}", fileObject);
imageAdapter.deleteFile(fileObject.getFullPath());
}); });
} }
public void cleanVideoOss() { public void cleanVideoOss() {