feat(sourcemap): 上传后自动裁剪,每版本保留最新 3 条,最多保留 5 个版本
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
523f9d7894
当前提交
d02cd10714
@ -20,6 +20,14 @@ public interface LogSourcemapRepository extends JpaRepository<LogSourcemapEntity
|
|||||||
Optional<LogSourcemapEntity> findFirstByAppKeyAndPlatformAndAppVersionAndBundleNameOrderByUploadedAtDesc(
|
Optional<LogSourcemapEntity> findFirstByAppKeyAndPlatformAndAppVersionAndBundleNameOrderByUploadedAtDesc(
|
||||||
String appKey, String platform, String appVersion, String bundleName);
|
String appKey, String platform, String appVersion, String bundleName);
|
||||||
|
|
||||||
|
/** All records for one version, newest first — used for per-version retention pruning. */
|
||||||
|
List<LogSourcemapEntity> findByAppKeyAndPlatformAndAppVersionAndBundleNameOrderByUploadedAtDesc(
|
||||||
|
String appKey, String platform, String appVersion, String bundleName);
|
||||||
|
|
||||||
|
/** All records for one (appKey, platform, bundleName), newest first — used for version-count pruning. */
|
||||||
|
List<LogSourcemapEntity> findByAppKeyAndPlatformAndBundleNameOrderByUploadedAtDesc(
|
||||||
|
String appKey, String platform, String bundleName);
|
||||||
|
|
||||||
List<LogSourcemapEntity> findByAppKey(String appKey);
|
List<LogSourcemapEntity> findByAppKey(String appKey);
|
||||||
|
|
||||||
void deleteByAppKey(String appKey);
|
void deleteByAppKey(String appKey);
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -103,6 +105,8 @@ public class SourcemapService {
|
|||||||
log.info("Sourcemap uploaded: appKey={} platform={} version={} buildId={} bundle={}",
|
log.info("Sourcemap uploaded: appKey={} platform={} version={} buildId={} bundle={}",
|
||||||
appKey, platform, versionKey, buildId, bundleName);
|
appKey, platform, versionKey, buildId, bundleName);
|
||||||
|
|
||||||
|
pruneSourcemaps(appKey, platform, appVersion, bundleName);
|
||||||
|
|
||||||
return new SourcemapUploadResponse(
|
return new SourcemapUploadResponse(
|
||||||
entity.getId(), entity.getAppKey(), entity.getPlatform(),
|
entity.getId(), entity.getAppKey(), entity.getPlatform(),
|
||||||
entity.getAppVersion(), entity.getBundleName(), entity.getBuildId(), entity.getStorageKey()
|
entity.getAppVersion(), entity.getBundleName(), entity.getBuildId(), entity.getStorageKey()
|
||||||
@ -157,6 +161,53 @@ public class SourcemapService {
|
|||||||
return findSourceMap(appKey, platform, appVersion, null, bundleName);
|
return findSourceMap(appKey, platform, appVersion, null, bundleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforce retention policy after every upload:
|
||||||
|
* - per version (appVersion): keep at most 3 records (newest by uploadedAt)
|
||||||
|
* - per (appKey, platform, bundleName): keep at most 5 distinct appVersions (newest by latest upload)
|
||||||
|
*/
|
||||||
|
private void pruneSourcemaps(String appKey, String platform, String appVersion, String bundleName) {
|
||||||
|
// 1. Per-version limit: keep newest 3 buildIds
|
||||||
|
List<LogSourcemapEntity> versionRecords = sourcemapRepository
|
||||||
|
.findByAppKeyAndPlatformAndAppVersionAndBundleNameOrderByUploadedAtDesc(
|
||||||
|
appKey, platform, appVersion, bundleName);
|
||||||
|
if (versionRecords.size() > 3) {
|
||||||
|
deleteEntities(versionRecords.subList(3, versionRecords.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Version-count limit: keep at most 5 distinct appVersions
|
||||||
|
List<LogSourcemapEntity> allRecords = sourcemapRepository
|
||||||
|
.findByAppKeyAndPlatformAndBundleNameOrderByUploadedAtDesc(appKey, platform, bundleName);
|
||||||
|
|
||||||
|
// Preserve insertion order = newest-first version order
|
||||||
|
LinkedHashSet<String> orderedVersions = new LinkedHashSet<>();
|
||||||
|
for (LogSourcemapEntity r : allRecords) {
|
||||||
|
orderedVersions.add(r.getAppVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderedVersions.size() > 5) {
|
||||||
|
List<String> versionList = new ArrayList<>(orderedVersions);
|
||||||
|
Set<String> versionsToDelete = new LinkedHashSet<>(versionList.subList(5, versionList.size()));
|
||||||
|
List<LogSourcemapEntity> excess = allRecords.stream()
|
||||||
|
.filter(r -> versionsToDelete.contains(r.getAppVersion()))
|
||||||
|
.toList();
|
||||||
|
deleteEntities(excess);
|
||||||
|
log.info("Pruned {} old-version sourcemap(s) for appKey={} platform={} bundle={}",
|
||||||
|
excess.size(), appKey, platform, bundleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteEntities(List<LogSourcemapEntity> entities) {
|
||||||
|
for (LogSourcemapEntity entity : entities) {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(Paths.get(entity.getStorageKey()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not delete sourcemap file {}: {}", entity.getStorageKey(), e.getMessage());
|
||||||
|
}
|
||||||
|
sourcemapRepository.delete(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String readSourceMapContent(String storageKey) throws IOException {
|
public String readSourceMapContent(String storageKey) throws IOException {
|
||||||
return Files.readString(Paths.get(storageKey));
|
return Files.readString(Paths.get(storageKey));
|
||||||
}
|
}
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户