perf: async OSS upload in resumable complete endpoint
For OSS storage, the /api/upload/resumable/complete endpoint now returns immediately after all chunks are assembled, then uploads to OSS in the background. This eliminates the blocking re-upload delay for large files. Local storage remains synchronous (already optimized with rename-first). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6460,10 +6460,57 @@ app.post('/api/upload/resumable/complete', authMiddleware, async (req, res) => {
|
|||||||
});
|
});
|
||||||
const storageInterface = new StorageInterface(storageUserContext);
|
const storageInterface = new StorageInterface(storageUserContext);
|
||||||
storage = await storageInterface.connect();
|
storage = await storageInterface.connect();
|
||||||
await storage.put(session.temp_file_path, session.target_path);
|
|
||||||
if (sessionStorageType === 'oss') {
|
if (sessionStorageType === 'oss') {
|
||||||
|
// OSS 模式:先标记会话为 finalizing 并立即返回响应,后台异步上传到 OSS
|
||||||
|
UploadSessionDB.setStatus(session.session_id, 'finalizing', {
|
||||||
|
completed: false,
|
||||||
|
expiresAt: buildResumableUploadExpiresAt(30 * 60 * 1000)
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: '分片上传完成,文件正在转存到云端',
|
||||||
|
path: session.target_path,
|
||||||
|
file_name: session.file_name,
|
||||||
|
file_size: fileSize
|
||||||
|
});
|
||||||
|
|
||||||
|
// 后台异步执行 OSS 上传,不阻塞客户端
|
||||||
|
const bgStorage = storage;
|
||||||
|
storage = null; // 防止 finally 提前关闭
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await bgStorage.put(session.temp_file_path, session.target_path);
|
||||||
clearOssUsageCache(req.user.id);
|
clearOssUsageCache(req.user.id);
|
||||||
|
UploadSessionDB.setStatus(session.session_id, 'completed', {
|
||||||
|
completed: true,
|
||||||
|
expiresAt: buildResumableUploadExpiresAt(60 * 1000)
|
||||||
|
});
|
||||||
|
safeUnlink(session.temp_file_path);
|
||||||
|
await trackFileHashIndexForUpload({
|
||||||
|
userId: req.user.id,
|
||||||
|
storageType: sessionStorageType,
|
||||||
|
fileHash: session.file_hash,
|
||||||
|
fileSize,
|
||||||
|
filePath: session.target_path
|
||||||
|
});
|
||||||
|
console.log(`[分片上传] OSS 后台转存完成: ${session.target_path}`);
|
||||||
|
} catch (bgError) {
|
||||||
|
console.error(`[分片上传] OSS 后台转存失败: ${session.target_path}`, bgError);
|
||||||
|
UploadSessionDB.setStatus(session.session_id, 'failed', {
|
||||||
|
completed: false,
|
||||||
|
expiresAt: buildResumableUploadExpiresAt(60 * 60 * 1000)
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
await bgStorage.end().catch(() => {});
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地存储:直接同步完成(rename-first 策略已优化,速度很快)
|
||||||
|
await storage.put(session.temp_file_path, session.target_path);
|
||||||
|
|
||||||
UploadSessionDB.setStatus(session.session_id, 'completed', {
|
UploadSessionDB.setStatus(session.session_id, 'completed', {
|
||||||
completed: true,
|
completed: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user