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

如何修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:07:42