如何避免Azure Function因Blob存储上传触发的递归执行问题
如何避免Azure Function因Blob存储上传触发的递归执行问题
我太懂你这个困扰了——自己生成的缩略图上传后又触发了同一个函数,陷入无限循环,还因为要存在同一个容器,没法靠容器名过滤。别着急,给你几个实用的解决思路,都是实际场景里验证过的:
方案一:利用Blob命名规则做Event Grid过滤(最省心)
既然你已经把缩略图命名成{原文件名}_t.扩展名的格式,那直接在Event Grid订阅里加个高级过滤,把带_t.的Blob上传事件排除掉就行:
- 打开你的Event Grid订阅配置,找到「高级过滤」部分
- 添加一条字符串过滤规则:
- 字段选择
data.blobName - 运算符选「不包含」
- 值填
_t.
这样只有原始图片的上传事件会触发函数,缩略图的上传直接被过滤,从根源上避免递归。
- 字段选择
方案二:给缩略图Blob加元数据,通过元数据过滤
如果以后你的缩略图命名规则可能变,那可以给生成的缩略图加自定义元数据,再在Event Grid里过滤掉带这个元数据的事件:
首先修改你代码里的上传逻辑,添加元数据:
try { await blockBlobClient.uploadStream(readStream, uploadOptions.bufferSize, uploadOptions.maxBuffers, { blobHTTPHeaders: { blobContentType: "image/jpeg" }, metadata: { "generated-by": "thumbnail-resizer" } // 新增自定义元数据 }); context.log(`File uploaded`); } catch (err) { context.log(err.message); }
然后回到Event Grid订阅的高级过滤,添加规则:
- 字段选
data.metadata.generated-by - 运算符选「不等于」
- 值填
thumbnail-resizer
这样只有没有这个元数据的原始Blob会触发函数,缩略图的上传事件直接被跳过。
方案三:在函数内部判断并跳过缩略图(兜底方案)
如果暂时没法修改Event Grid配置,那可以在函数开头加个判断,直接跳过缩略图的处理:
module.exports = async (context, event, inputBlob) => { context.log(`Function started`); const blobFileName = context.bindingData.data.blobName; // 先判断是不是缩略图,是就直接结束函数 if (blobFileName.includes("_t.")) { context.log(`跳过缩略图文件:${blobFileName}`); return; // 直接返回,不执行后续逻辑 } // 下面是你原来的处理逻辑... context.log(`event: ${JSON.stringify(event)}`); const widthInPixels = 100; const blobUrl = context.bindingData.data.url; const blobUrlArray = blobUrl.split("/"); const blobExt = blobFileName.slice(blobFileName.lastIndexOf(".") + 1); const blobName = blobFileName.slice(0, blobFileName.lastIndexOf(".")); const blobName_thumb = `${blobName}_t.${blobExt}`; const containerName = blobUrlArray[blobUrlArray.length - 2]; const image = await Jimp.read(inputBlob); const thumbnail = image.resize(widthInPixels, Jimp.AUTO); const thumbnailBuffer = await thumbnail.getBufferAsync(Jimp.AUTO); const readStream = stream.PassThrough(); readStream.end(thumbnailBuffer); const containerClient = blobServiceClient.getContainerClient(containerName); const blockBlobClient = containerClient.getBlockBlobClient(blobName_thumb); context.log(`blockBlobClient created`); try { await blockBlobClient.uploadStream(readStream, uploadOptions.bufferSize, uploadOptions.maxBuffers, { blobHTTPHeaders: { blobContentType: "image/jpeg" } }); context.log(`File uploaded`); } catch (err) { context.log(err.message); } finally { context.done(); } };
这个方案不需要动外部配置,直接在代码里拦截,适合临时快速解决问题。
备注:内容来源于stack exchange,提问作者M.mhr
相关产品推荐
相关产品推荐

