影像恢复代码
continuous-integration/drone/push Build is passing Details

Test_IRC_Net8
hang 2026-01-08 10:09:19 +08:00
parent eca7871684
commit fbd128138d
3 changed files with 99 additions and 156 deletions

View File

@ -144,7 +144,7 @@ public enum ObjectStoreUse
public interface IOSSService
{
public Task SetImmediateArchiveRule(string prefix, string ruleId = "immediate-archive", bool isDelete = false);
public Task RestoreFilesByPrefixAsync(string prefix, int restoreDays = 3, int batchSize = 100);
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
@ -384,10 +384,7 @@ public class OSSService : IOSSService
/// <param name="restoreDays">解冻后文件保持可读的天数默认3天</param>
/// <param name="restoreTier">解冻优先级仅AWS有效</param>
/// <param name="batchSize">批量处理大小默认100</param>
public async Task RestoreFilesByPrefixAsync(string prefix,
int restoreDays = 3,
string restoreTier = "Standard",
int batchSize = 100)
public async Task RestoreFilesByPrefixAsync(string prefix, int restoreDays = 3, int batchSize = 100)
{
BackBatchGetToken();
@ -410,6 +407,8 @@ public class OSSService : IOSSService
{
Console.WriteLine($"开始解冻阿里云OSS文件前缀: {prefix}");
var allObjects = new List<OssObjectSummary>();
// 1. 分页列举文件
string nextMarker = null;
ObjectListing result = null;
@ -425,74 +424,56 @@ public class OSSService : IOSSService
result = client.ListObjects(listRequest);
// 2. 批量处理每个文件
var restoreTasks = new List<Task>();
allObjects.AddRange(result.ObjectSummaries);
foreach (var obj in result.ObjectSummaries)
{
// 跳过非归档/冷归档文件
if (obj.StorageClass != StorageClass.Archive.ToString())
{
Console.WriteLine($"跳过非归档文件: {obj.Key} (类型: {obj.StorageClass})");
totalSkipped++;
continue;
}
// 提交解冻任务
var task = Task.Run(() =>
{
try
{
var restoreRequest = new Aliyun.OSS.RestoreObjectRequest(bucketName, obj.Key)
{
Days = restoreDays
};
client.RestoreObject(restoreRequest);
Interlocked.Increment(ref totalRestored);
Console.WriteLine($"✅ 已提交解冻: {obj.Key} (天数: {restoreDays})");
}
catch (OssException ex)
{
if (ex.ErrorCode == "RestoreAlreadyInProgress")
{
Console.WriteLine($"⚠️ 解冻已在进行中: {obj.Key}");
}
else
{
Interlocked.Increment(ref totalFailed);
Console.WriteLine($"❌ 解冻失败 [{obj.Key}]: {ex.Message}");
}
}
catch (Exception ex)
{
Interlocked.Increment(ref totalFailed);
Console.WriteLine($"❌ 解冻失败 [{obj.Key}]: {ex.Message}");
}
});
restoreTasks.Add(task);
// 控制并发,避免请求过快
if (restoreTasks.Count >= 10) // 并发10个任务
{
await Task.WhenAll(restoreTasks);
restoreTasks.Clear();
await Task.Delay(100); // 短暂延迟
}
}
// 等待剩余任务完成
if (restoreTasks.Count > 0)
{
await Task.WhenAll(restoreTasks);
}
nextMarker = result.NextMarker;
} while (result.IsTruncated);
// 2⃣ 并行解冻(控制并发)
Parallel.ForEach(
allObjects,
new ParallelOptions
{
MaxDegreeOfParallelism = 5 // ⭐ 推荐 5~10
},
obj =>
{
// 只处理归档
if (obj.StorageClass != StorageClass.Archive.ToString())
{
Interlocked.Increment(ref totalSkipped);
return;
}
try
{
var restoreRequest = new Aliyun.OSS.RestoreObjectRequest(bucketName, obj.Key)
{
Days = restoreDays
};
client.RestoreObject(restoreRequest);
Interlocked.Increment(ref totalRestored);
Console.WriteLine($"✅ 提交解冻: {obj.Key}");
}
catch (OssException ex) when (ex.ErrorCode == "RestoreAlreadyInProgress")
{
// 已在解冻中,算成功
Interlocked.Increment(ref totalSkipped);
Console.WriteLine($"⚠️ 已在解冻中: {obj.Key}");
}
catch (Exception ex)
{
Interlocked.Increment(ref totalFailed);
Console.WriteLine($"❌ 解冻失败: {obj.Key} - {ex.Message}");
}
}
);
// 3. 输出统计结果
Console.WriteLine("\n================ 解冻完成 ================");
Console.WriteLine($"总计处理: {totalRestored + totalSkipped + totalFailed} 个文件");
@ -540,6 +521,8 @@ public class OSSService : IOSSService
{
Console.WriteLine($"开始解冻AWS S3文件前缀: {prefix}");
var allObjects = new List<S3Object>();
// 1. 分页列举文件
string continuationToken = null;
ListObjectsV2Response response = null;
@ -556,100 +539,58 @@ public class OSSService : IOSSService
response = await client.ListObjectsV2Async(listRequest);
// 2. 批量处理每个文件
var restoreTasks = new List<Task>();
allObjects.AddRange(response.S3Objects);
foreach (var obj in response.S3Objects)
{
// 需要先获取对象元数据以确定存储类型
var metadataRequest = new Amazon.S3.Model.GetObjectMetadataRequest
{
BucketName = bucketName,
Key = obj.Key
};
try
{
var metadata = await client.GetObjectMetadataAsync(metadataRequest);
// 检查是否为归档类型
bool isGlacierObject = metadata.StorageClass == S3StorageClass.Glacier;
if (!isGlacierObject)
{
Console.WriteLine($"跳过非归档文件: {obj.Key} (类型: {metadata.StorageClass})");
totalSkipped++;
continue;
}
// 提交解冻任务
var task = Task.Run(async () =>
{
try
{
var restoreRequest = new Amazon.S3.Model.RestoreObjectRequest
{
BucketName = bucketName,
Key = obj.Key,
Days = restoreDays
};
await client.RestoreObjectAsync(restoreRequest);
Interlocked.Increment(ref totalRestored);
Console.WriteLine($"✅ 已提交解冻: {obj.Key} (天数: {restoreDays}, 优先级: {restoreTier})");
}
catch (AmazonS3Exception ex)
{
if (ex.ErrorCode == "RestoreAlreadyInProgress")
{
Console.WriteLine($"⚠️ 解冻已在进行中: {obj.Key}");
}
else if (ex.ErrorCode == "AccessDenied")
{
Interlocked.Increment(ref totalFailed);
Console.WriteLine($"❌ 权限不足 [{obj.Key}]: 需要 s3:RestoreObject 权限");
}
else
{
Interlocked.Increment(ref totalFailed);
Console.WriteLine($"❌ 解冻失败 [{obj.Key}]: {ex.Message}");
}
}
catch (Exception ex)
{
Interlocked.Increment(ref totalFailed);
Console.WriteLine($"❌ 解冻失败 [{obj.Key}]: {ex.Message}");
}
});
restoreTasks.Add(task);
// 控制并发
if (restoreTasks.Count >= 5) // AWS建议较低并发
{
await Task.WhenAll(restoreTasks);
restoreTasks.Clear();
await Task.Delay(200); // AWS有速率限制
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 获取元数据失败 [{obj.Key}]: {ex.Message}");
totalFailed++;
}
}
// 等待剩余任务
if (restoreTasks.Count > 0)
{
await Task.WhenAll(restoreTasks);
}
continuationToken = response.NextContinuationToken;
} while (response.IsTruncated == true);
// 2⃣ 并行解冻(控制并发)
await Parallel.ForEachAsync(
allObjects,
new ParallelOptions
{
MaxDegreeOfParallelism = 5 // ⭐ 推荐 5~10
},
async (obj, ct) =>
{
// 只处理归档
if (obj.StorageClass != S3StorageClass.Glacier)
{
Interlocked.Increment(ref totalSkipped);
return;
}
try
{
var restoreRequest = new Amazon.S3.Model.RestoreObjectRequest
{
BucketName = bucketName,
Key = obj.Key,
Days = restoreDays,
};
await client.RestoreObjectAsync(restoreRequest);
Interlocked.Increment(ref totalRestored);
Console.WriteLine($"✅ 提交解冻: {obj.Key}");
}
catch (OssException ex) when (ex.ErrorCode == "RestoreAlreadyInProgress")
{
// 已在解冻中,算成功
Interlocked.Increment(ref totalSkipped);
Console.WriteLine($"⚠️ 已在解冻中: {obj.Key}");
}
catch (Exception ex)
{
Interlocked.Increment(ref totalFailed);
Console.WriteLine($"❌ 解冻失败: {obj.Key} - {ex.Message}");
}
}
);
// 3. 输出统计结果
Console.WriteLine("\n================ 解冻完成 ================");
Console.WriteLine($"总计处理: {totalRestored + totalSkipped + totalFailed} 个文件");

View File

@ -15748,7 +15748,7 @@
<param name="ruleId">规则ID默认为"immediate-archive"</param>
<param name="isDelete">默认是添加/更新 </param>
</member>
<!-- Badly formed XML comment ignored for member "M:IRaCIS.Core.Application.Helper.OSSService.RestoreFilesByPrefixAsync(System.String,System.Int32,System.String,System.Int32)" -->
<!-- Badly formed XML comment ignored for member "M:IRaCIS.Core.Application.Helper.OSSService.RestoreFilesByPrefixAsync(System.String,System.Int32,System.Int32)" -->
<member name="M:IRaCIS.Core.Application.Helper.OSSService.SetLifecycle(System.String,System.String)">
<summary>
坑方法,会清空之前的规则

View File

@ -80,7 +80,9 @@ namespace IRaCIS.Core.Application.Service
{
if (storageClass == StorageClass.IA || storageClass == StorageClass.Archive || storageClass == StorageClass.ColdArchive || storageClass == StorageClass.DeepColdArchive)
{
_IOSSService.SetImmediateArchiveRule($"Test-Archive/Archive{(int)storageClass}/");
//await _IOSSService.SetImmediateArchiveRule($"Test-Archive/Archive{(int)storageClass}/");
await _IOSSService.RestoreFilesByPrefixAsync($"Test-Archive/Archive{(int)storageClass}/");
}