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

Azure Blob Trigger通过SFTP上传时触发两次问题求助

Azure Blob Trigger SFTP上传重复触发问题解决方案

问题原因

SFTP客户端上传文件时,通常会分阶段操作:比如先创建空的目标文件再逐步写入内容,或是先上传临时文件、完成后重命名为目标文件名。这两种操作都会让Azure Blob存储生成两次BlobCreated事件,导致Trigger被触发两次。而手动上传时Azure门户的机制是一次性完成文件写入,只会触发一次事件。

解决方法

  • 基于ETag校验过滤重复触发
    在函数逻辑中先验证Blob是否处于稳定状态(上传完成),再执行业务逻辑。可以通过对比触发时的ETag和实时获取的Blob ETag来判断:

    public static async Task Run(
        [BlobTrigger("your-container/{name}", Connection = "AzureWebJobsStorage")] Stream myBlob,
        string name,
        string etag,
        ILogger log)
    {
        // 短暂延迟确保文件上传完成,时长根据实际场景调整
        await Task.Delay(1500);
    
        var blobClient = new BlobServiceClient(Environment.GetEnvironmentVariable("AzureWebJobsStorage"))
                            .GetBlobContainerClient("your-container")
                            .GetBlobClient(name);
        var currentProps = await blobClient.GetPropertiesAsync();
    
        // 如果ETag不一致,说明文件还在更新中,跳过处理
        if (currentProps.ETag.ToString() != etag)
        {
            log.LogInformation($"File {name} is still uploading, skip this trigger.");
            return;
        }
    
        // 执行你的业务逻辑
        log.LogInformation($"Processing file: {name}");
    }
    
  • 配置Blob Trigger过滤规则
    在host.json中开启忽略空Blob的设置,避免空文件触发事件,同时确认只监听BlobCreated事件:

    {
      "version": "2.0",
      "extensions": {
        "blobs": {
          "trigger": {
            "ignoreEmptyBlobs": true,
            "blobCreatedEventTypes": ["Microsoft.Storage.BlobCreated"]
          }
        }
      }
    }
    
  • 调整SFTP客户端上传模式
    检查你的SFTP客户端设置,关闭“原子上传”或“临时文件重命名”功能,改为直接覆盖目标文件。这样上传过程只会生成一次Blob事件,但需注意如果上传中断会导致文件损坏,需根据业务场景权衡。

  • 分布式锁避免多实例重复处理
    如果函数部署了多实例,可利用Blob租约实现分布式锁,确保同一个文件只有一个实例处理:

    public static async Task Run(
        [BlobTrigger("your-container/{name}", Connection = "AzureWebJobsStorage")] Stream myBlob,
        string name,
        ILogger log)
    {
        var blobClient = new BlobServiceClient(Environment.GetEnvironmentVariable("AzureWebJobsStorage"))
                            .GetBlobContainerClient("your-container")
                            .GetBlobClient(name);
    
        // 尝试获取Blob租约,租期1分钟
        try
        {
            using var lease = await blobClient.AcquireLeaseAsync(TimeSpan.FromMinutes(1));
            // 执行业务逻辑
            log.LogInformation($"Processing file {name} with lease: {lease.LeaseId}");
        }
        catch (RequestFailedException ex) when (ex.Status == 409)
        {
            // 租约已被其他实例获取,跳过处理
            log.LogInformation($"File {name} is being processed by another instance, skip.");
        }
    }
    

关于FixedDelayRetry无效的说明

[FixedDelayRetry(0, "00:00:10")]是用来控制函数执行失败后的重试行为,而你遇到的是两次独立的触发事件,并非单次触发后的重试,所以这个属性无法解决重复触发问题。

内容的提问来源于stack exchange,提问作者Furkan Moray

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 23:01:53