【问题标题】:Firebase function time-out when streaming file from Firebase Storage on emulator从模拟器上的 Firebase 存储流式传输文件时 Firebase 功能超时
【发布时间】:2020-12-12 01:04:40
【问题描述】:

我是 node.js 和一般后端的新手,并试图为我的宠物项目提供下载文件的 API。为此,我决定在 Firebase 存储中托管文件,并通过 Firebase Functions 提供对它们的访问。为此,我使用以下代码:

const app = express()

app.get('/:filename', async (request, response) => {
  const file = await admin.storage().bucket().getFiles({
    autoPaginate: false,
    delimiter: '/',
    prefix: 'files/'
  })
  .then(response => {
    const files = response[0]
    files.shift()
    return files[0] //let's take first file for example
  })

  response.attachment(`${filename}.zip`);
  response.setHeader('Content-Type', `${file.metadata.type}`) // application/zip
  response.setHeader('Content-Length', file.metadata.size)

  file.createReadStream()
  .pipe(response)
})

exports.styles = functions.https.onRequest(app)

就下载文件的能力而言,当从浏览器访问 URL 并在下载后打开它时,一切正常,所以这里没有问题。

让我烦恼的是,在提供文件和下载完成后,功能并没有结束。相反,它会在模拟器上引发超时错误(尚未部署此功能,因此无法确定它是否可以在现场重现)。

⚠  functions: Your function timed out after ~60s. To configure this timeout, see
      https://firebase.google.com/docs/functions/manage-functions#set_timeout_and_memory_allocation.
>  /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:642
>                  throw new Error("Function timed out.");
>                  ^
>  
>  Error: Function timed out.
>      at Timeout._onTimeout (/usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:642:23)
>      at listOnTimeout (internal/timers.js:551:17)
>      at processTimers (internal/timers.js:494:7)

我也试过以下sn-p,但结果是一样的:

file.createReadStream()
  .on('end', () => {
    console.log("end reading file stream. closing connection")
    response.end(() => console.log("connection closed"))
  })
  .pipe(response)

此外,第一个和第二个日志语句都不会打印。 有趣的是,部署脚本时不会重现此问题,仅在模拟器上发生。

我对此做了一些研究,发现在流期间触发了一些事件,可以处理并做response.end(),但显然在管道时不需要这样做。

我现在被困住了,因此感谢您的帮助。

【问题讨论】:

  • 作为最佳实践,您必须在 .then() 之后使用 .catch() 处理 Cloud Functions 中的错误,以更好地管理和解决 errors。另外请按照以下答案正确结束您的云功能。

标签: node.js typescript firebase google-cloud-functions firebase-storage


【解决方案1】:

尝试在你的函数中设置超时:

const runtimeOpts = {
  timeoutSeconds: 300
}

exports.styles = functions.runWith(runtimeOpts).https.onRequest(app)

timeoutSeconds 的最大值为 540,即 9 分钟

【讨论】:

    【解决方案2】:

    Firebase Official documentation 声明我们必须确保函数正确终止:

    使用 res.redirect()、res.send() 或 res.end() 终止 HTTP 函数。

    所以检查 createReadStream 何时“结束”,然后调用响应的 end() 函数。

    file.createReadStream()
      .on('end', function() {
        response.end();
      })
      .pipe(response);
    

    【讨论】:

    • 感谢您的回答。我实际上已经尝试过了,但这没有用。我仍然收到超时错误。我将更新 OP 以包含此详细信息。顺便说一句,我在 OP 中提到,在我的研究过程中,我偶然发现了一篇文章,说当管道到 response 时,不需要手动关闭。是针对具体节点版本还是一般?
    • 其他可以尝试的是return response.end(); 你实际上可以返回整个东西。 return file.createReadStream().on(...)
    猜你喜欢
    • 1970-01-01
    • 2018-06-02
    • 2018-11-17
    • 1970-01-01
    • 2020-02-05
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 2020-07-05
    相关资源
    最近更新 更多