影像恢复代码
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
eca7871684
commit
fbd128138d
|
|
@ -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} 个文件");
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
坑方法,会清空之前的规则
|
||||
|
|
|
|||
|
|
@ -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}/");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue