如何修改Azure Durable Function模板接收70MB文件并传递给编排函数
解决Azure Durable Functions HttpStart处理大文件内存溢出问题
问题根源
默认的HttpStart模板会一次性将整个请求体加载到内存中构建req对象,70MB文件在Node.js默认堆内存配置下容易触发内存溢出错误。同时Durable Orchestration的输入本身有大小限制(建议不超过16KB),直接传递大文件内容也不符合最佳实践。
解决方案步骤
1. 改用Blob存储中转文件
不要直接将文件内容传递给编排函数,先将文件上传到Azure Blob存储,再把Blob的访问信息(如SAS URL或容器+Blob名称)传给编排函数,让编排函数后续从Blob读取文件处理。
2. 修改HttpStart函数为流式处理
修改HttpStart代码,避免一次性加载整个请求体到内存,改为流式读取请求内容并直接上传到Blob存储:
首先安装Azure Blob存储依赖:
npm install @azure/storage-blob
替换HttpStart的代码:
const df = require("durable-functions"); const { BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions } = require("@azure/storage-blob"); const { v4: uuidv4 } = require("uuid"); module.exports = async function (context, req) { const client = df.getClient(context); const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.AzureWebJobsStorage); const containerName = "file-uploads"; // 替换为预先创建的Blob容器名称 const containerClient = blobServiceClient.getContainerClient(containerName); // 生成唯一Blob名称 const blobName = `${uuidv4()}-${req.headers["content-disposition"]?.split("filename=")[1] || "uploaded-file"}`; const blockBlobClient = containerClient.getBlockBlobClient(blobName); // 流式上传请求体到Blob,不加载整个文件到内存 await blockBlobClient.uploadStream(req, undefined, undefined, { blobHTTPHeaders: { blobContentType: req.headers["content-type"] } }); // 生成Blob的SAS URL(供编排函数访问) const sasToken = generateBlobSASQueryParameters({ containerName, blobName, permissions: BlobSASPermissions.parse("r"), expiresOn: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7天有效期 }, blobServiceClient.credential).toString(); const sasUrl = `${blockBlobClient.url}?${sasToken}`; // 启动编排函数,传入Blob信息 const instanceId = await client.startNew(req.params.functionName, undefined, { blobUrl: sasUrl, blobName, containerName }); context.log(`Started orchestration with ID = '${instanceId}'.`); return client.createCheckStatusResponse(context.bindingData.req, instanceId); };
3. 调整函数应用配置
- 增加Node.js堆内存:在函数应用配置中添加应用设置
NODE_OPTIONS,值设为--max-old-space-size=1408(消费计划最大可用内存1.5GB,此值适配该限制) - 调整请求体大小限制:修改
host.json中的http请求配置:
{ "version": "2.0", "extensions": { "http": { "maxRequestSize": "100MB" } } }
4. 修改编排函数逻辑
编排函数不再接收文件内容,而是通过传入的Blob信息从存储读取文件,执行fan-out/fan-in处理:
const df = require("durable-functions"); const { BlobServiceClient } = require("@azure/storage-blob"); module.exports = df.orchestrator(function*(context) { const input = context.df.getInput(); const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.AzureWebJobsStorage); const blockBlobClient = blobServiceClient.getBlockBlobClient(input.containerName, input.blobName); // 读取Blob内容(按需拆分处理) const downloadResponse = yield context.df.callActivity("ReadBlobContent", input.blobUrl); const fileChunks = splitFileIntoChunks(downloadResponse.content); // 自定义拆分逻辑 // 启动并行任务 const tasks = fileChunks.map(chunk => context.df.callActivity("ProcessChunk", chunk)); const results = yield context.df.Task.all(tasks); return results; });
关键注意事项
- 提前创建Blob容器,生产环境建议用托管身份而非连接字符串授权函数访问Blob存储
- 始终保持编排函数输入最小化,仅传递元数据而非大文件内容
- 流式处理是避免内存溢出的核心,禁止将大请求体转换为Buffer或字符串
内容的提问来源于stack exchange,提问作者SJT
相关产品推荐
相关产品推荐

