You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Azure Function上传至Amazon S3时进度无法达到100%

解决S3上传进度无法达到100%的问题

我之前做类似的跨云Blob传输时,也碰到过AWS SDK进度事件不触发100%的情况,结合你的场景,主要有几个可能的原因和对应的解决办法:

1. AWS SDK进度事件的触发逻辑限制

AWS .NET SDK的UploadProgressEvent在分块上传场景下,只会在每个分块传输完成时触发。当最后一个分块传输完成后,SDK还会执行合并分块的操作,但这一步的字节传输不会被计入UploadProgressArgs,也不会触发额外的进度事件。这就导致即使总传输字节数已经等于文件大小,最后一次触发的进度百分比可能还是不到100%(比如99%)。

解决办法:
在上传任务完成后(比如UploadAsync方法执行完毕),手动补充一条100%的进度记录。因为此时上传已经完全完成,不管进度事件有没有触发,都可以直接标记完成状态。

2. EF同步操作阻塞了事件线程

你在uploadRequest_UploadPartProgressEvent里直接用EF做同步数据库写入,这个操作是耗时的,会阻塞SDK用来触发进度事件的线程。如果线程被长时间占用,SDK可能会跳过后续的进度通知(包括最后100%的触发)。

解决办法:

  • 把EF操作改成异步模式,用await _context.SaveChangesAsync()替代同步的SaveChanges(),避免阻塞线程。
  • 尽量不要在进度事件处理程序里做耗时操作,可将日志任务放入后台队列(比如Azure Function的IBackgroundTaskQueue),让SDK的上传流程不受影响。

3. 进度计算的精度问题

有时候因为分块大小的计算,PercentDone可能会因为取整逻辑显示为99%,但实际BytesTransferred已经等于TotalBytesToTransfer。这时候可以通过字节数来判断是否完成,而不是依赖百分比。

示例代码调整

// 异步进度事件处理程序
private async void uploadRequest_UploadPartProgressEvent(object sender, UploadProgressArgs e)
{
    using var scope = _serviceProvider.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService<YourDbContext>();
    
    var progressLog = new UploadProgressLog
    {
        UploadId = "你的上传标识",
        BytesTransferred = e.BytesTransferred,
        Percentage = e.BytesTransferred == e.TotalBytesToTransfer ? 100 : e.PercentDone,
        Timestamp = DateTime.UtcNow
    };
    
    context.UploadProgressLogs.Add(progressLog);
    await context.SaveChangesAsync();
}

// 上传完成后补全100%进度
public async Task UploadToS3Async(Stream blobStream, string s3Key)
{
    var uploadRequest = new TransferUtilityUploadRequest
    {
        InputStream = blobStream,
        Key = s3Key,
        BucketName = "你的S3桶名",
    };
    uploadRequest.UploadProgressEvent += uploadRequest_UploadPartProgressEvent;
    
    var transferUtility = new TransferUtility(_s3Client);
    await transferUtility.UploadAsync(uploadRequest);
    
    // 上传完成后检查并补全100%进度
    using var scope = _serviceProvider.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService<YourDbContext>();
    var latestLog = await context.UploadProgressLogs
        .Where(l => l.UploadId == "你的上传标识")
        .OrderByDescending(l => l.Timestamp)
        .FirstOrDefaultAsync();
    
    if (latestLog == null || latestLog.Percentage != 100)
    {
        context.UploadProgressLogs.Add(new UploadProgressLog
        {
            UploadId = "你的上传标识",
            BytesTransferred = blobStream.Length,
            Percentage = 100,
            Timestamp = DateTime.UtcNow
        });
        await context.SaveChangesAsync();
    }
}

另外要注意,在Azure Function中使用EF时,要通过依赖注入正确管理上下文生命周期,避免在事件处理程序中持有长生命周期的上下文实例,防止出现资源泄漏或者并发问题。

内容的提问来源于stack exchange,提问作者Dan Young

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:46:20