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

Azure WebJob中Stream.CopyTo执行时文件被锁定问题求助

队列触发WebJob大文件下载锁冲突问题解决

可能的触发原因

  • Windows App Service默认启用的Antimalware扫描进程会在文件创建后立即扫描,大文件写入过程中被扫描进程锁定。
  • FileShare.None的严格权限设置完全禁止其他进程访问,哪怕是系统服务也会触发冲突。
  • 队列触发的WebJob存在并发实例,多个进程同时尝试操作同一个目标文件。
  • Azure App Service的网络挂载存储(如D:\home)存在文件锁释放延迟,导致后续操作误以为文件仍被占用。

具体解决方案

1. 改用临时文件+原子重命名(优先推荐)

先将文件写入临时路径,完成后再重命名到目标位置,这是避免中间状态锁冲突的原子操作:

ShareFileClient file = shareDir.GetFileClient($"{list}.dat");
if (!file.Exists())
{
    logger.LogError($"ERROR: Couldn't find {list}.dat file in the file share.");
    return;
}

try
{
    string tempFilePath = Path.Combine(downloadPath, $"{list}.tmp");
    ShareFileDownloadInfo download = file.Download();
    using (FileStream fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
    {
        download.Content.CopyTo(fs);
    }
    // 重命名操作是原子性的,避免扫描进程锁定中间状态的文件
    File.Move(tempFilePath, Path.Combine(downloadPath, $"{list}.dat"), overwrite: true);
}
catch (Exception ex)
{
    logger.LogError($"EXCEPTION: An exception occurred while downloading {list}.dat.{Environment.NewLine}{ex.Message}{Environment.NewLine}{ex.InnerException?.Message ?? ""}");
    // 清理临时文件
    string tempFilePath = Path.Combine(downloadPath, $"{list}.tmp");
    if (File.Exists(tempFilePath)) File.Delete(tempFilePath);
    return;
}

2. 调整FileStream共享权限

将FileShare.None改为FileShare.Read,允许系统扫描进程读取文件,避免锁冲突:

using (FileStream fs = new FileStream(Path.Combine(downloadPath, $"{list}.dat"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
{
    download.Content.CopyTo(fs);
}

3. 控制WebJob并发

如果是多实例并发导致的冲突,在WebJob根目录创建settings.job文件,强制单实例运行:

{
  "is_singleton": true
}

或者使用Azure Blob分布式锁,确保同一时间只有一个进程处理目标文件。

4. 分块写入优化大文件

对于1.5GB的大文件,分块写入可以减少锁持有时间,同时降低内存占用:

using (FileStream fs = new FileStream(Path.Combine(downloadPath, $"{list}.dat"), FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
{
    byte[] buffer = new byte[81920]; // 80KB缓冲区
    int bytesRead;
    while ((bytesRead = download.Content.Read(buffer, 0, buffer.Length)) > 0)
    {
        fs.Write(buffer, 0, bytesRead);
        fs.Flush(); // 及时刷新缓冲区,缩短锁持有时间
    }
}

5. 临时关闭Antimalware扫描(谨慎使用)

如果确认是杀毒扫描导致的问题,可以在App Service应用设置中添加:

  • WEBSITE_DISABLE_SCM_SECURITY_SCAN = true
  • WEBSITE_DISABLE_FTP_SECURITY_SCAN = true
    注意:此操作会降低应用安全性,仅在测试或确认无风险场景下使用。

验证建议

  • 查看App Service诊断工具的Process Explorer,确认占用文件的进程(通常是MsMpEng.exe,Windows Defender)。
  • 检查WebJob运行日志,确认是否存在多实例并发启动的记录。

内容的提问来源于stack exchange,提问作者Disco Globeulon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:43:20