简体   繁体   English

错误:已超过期限 - 调用 firebase 可调用云 function (onCall) 时。 onRequest 工作正常

[英]Error: deadline-exceeded - when calling a firebase callable cloud function (onCall). onRequest works fine

I'm getting a "deadline-exceeded" error on the frontend when calling a firebase callable cloud function (onCall).调用 firebase 可调用云 function (onCall) 时,我在前端收到“超出期限”错误。

I know that I have to return a Promise so the function knows when to clean itself, but it is still not working.我知道我必须退回 Promise 以便 function 知道何时清理自己,但它仍然无法正常工作。

After 60 seconds, "deadline-exceeded" is throw to the frontend but the function keeps running on the server and finish with success. 60 秒后,“deadline-exceeded”被抛出到前端,但 function 继续在服务器上运行并成功完成。 All batch operations are written to the firestore.所有批处理操作都写入 Firestore。

10:37:14.782 AM
syncExchangeOperations
Function execution took 319445 ms, finished with status code: 200
10:36:57.323 AM
syncExchangeOperations
Function execution started
10:36:57.124 AM
syncExchangeOperations
Function execution took 170 ms, finished with status code: 204
10:36:56.955 AM
syncExchangeOperations
Function execution started
async function syncBinanceOperations(
  userId,
  userExchange,
  userExchangeLastOperations,
  systemExchange
) {
  try {
    const client = Binance({
      apiKey: userExchange.apiKey,
      apiSecret: userExchange.privateKey
    });

    const batch = admin.firestore().batch();
    const lastOperations = userExchangeLastOperations
      ? userExchangeLastOperations
      : false;

    const promises = [];

    promises.push(
      syncBinanceTrades(client, lastOperations, userId, systemExchange, batch)
    );
    promises.push(
      syncBinanceDeposits(client, lastOperations, userId, systemExchange, batch)
    );
    promises.push(
      syncBinanceWhitdraws(
        client,
        lastOperations,
        userId,
        systemExchange,
        batch
      )
    );
    promises.push(
      updateUserExchange(userId, userExchange.id, {
        lastSync: moment().format('x')
      })
    );

    await Promise.all(promises);
    return batch.commit();
  } catch (error) {
    return handleErrors(error);
  }
}

exports.syncExchangeOperations = functions.https.onCall(
  async (data, context) => {
    try {
      userAuthenthication(data.userId, context.auth);
      let user = await getUser(data.userId);

      if (!user.plan.benefits.syncExchanges) {
        throw 'Operação não autorizada para o plano contratado';
      }

      let userExchange = await getUserExchange(data.userId, data.exchangeId);

      let response = await Promise.all([
        getUserLastOperations(data.userId, userExchange.exchangeId),
        getSystemExchange(userExchange.exchangeId)
      ]);

      let userExchangeLastOperations = response[0];
      let systemExchange = response[1];

      switch (systemExchange.id) {
        case 'binance':
          return syncBinanceOperations(
            user.id,
            userExchange,
            userExchangeLastOperations,
            systemExchange
          );
      }
    } catch (error) {
      return handleErrors(error);
    }
  }
);

It works fine if I change this function to a HTTP request.如果我将此 function 更改为 HTTP 请求,它工作正常。 It waits the function to finish and returns.它等待 function 完成并返回。

exports.syncExchangeOperations = functions
  .runWith(runtimeOpts)
  .https.onRequest((req, res) => {
    return cors(req, res, async () => {
      try {
        let auth = await admin.auth().verifyIdToken(req.get('Authorization').split('Bearer ')[1]);

        let userExchange = await getUserExchange(
          auth.uid,
          req.query.exchangeId
        );

        let response = await Promise.all([
          getUserLastOperations(auth.uid, userExchange.exchangeId),
          getSystemExchange(userExchange.exchangeId)
        ]);

        let userExchangeLastOperations = response[0];
        let systemExchange = response[1];

        switch (systemExchange.id) {
          case 'binance':
            await syncBinanceOperations(
              auth.uid,
              userExchange,
              userExchangeLastOperations,
              systemExchange
            );
        }
        res.status(200).send();
      } catch (error) {
        res.status(401).send(handleErrors(error));
      }
    });
  });

"Deadline exceeded" means that the function invocation timed out from the perspective of the client. “超过截止日期”意味着从客户端的角度来看,function 调用超时。 The default is 60 seconds.默认值为 60 秒。

Try increasing the timeout on both the client and function so that it has time to complete before the client timeout is reached.尝试增加客户端和 function 的超时,以便在达到客户端超时之前有时间完成。 You can do this by specifying it in an HttpsCallableOptions object.您可以通过在 HttpsCallableOptions object 中指定它来执行此操作。

Also try returning something other than batch.commit() .也尝试返回batch.commit()以外的东西。 Whatever that function return will be serialized and sent to the client, which could cause problems.无论 function 返回什么都将被序列化并发送到客户端,这可能会导致问题。 Instead, just await batch.commit() then return something predictable, like a plain JavaScript object.相反,只需await batch.commit()然后返回可预测的内容,例如普通的 JavaScript object。

See the API documentation for information on setting the timeout:有关设置超时的信息,请参阅 API 文档:

The "deadline-exeeded" that you encountered is an error thrown by the Firebase Javascript library on the client (not the function itself).您遇到的“deadline-exeeded”是客户端上的 Firebase Javascript 库(不是 function 本身)引发的错误。 The Firebase docs are lacking documentation o how to use functions.runWithOptions() on a callable function. Firebase 文档缺少关于如何在可调用的 function 上使用functions.runWithOptions()的文档。 For some reason the functions().httpsCallable() has a built in timeout on the client side.由于某种原因, functions().httpsCallable()在客户端有一个内置的超时。

So if you use this on your Node.js function :因此,如果您在Node.js function上使用它:

exports.testFunction = functions.runWith({ timeoutSeconds: 180 }).https.onCall(async (data, ctx) => {
// Your Function Code that takes more than 60second to run
});

You need to override the buit in Javascript Library timeout on the client like this:您需要在客户端上覆盖Javascript 库超时中的 buit,如下所示:

let testFunction = firebase.functions().httpsCallable("testFunction", {timeout: 180000});

I don't know what is the purpose of the built in timeout on the client, for me it has no purpose since it doesn't even stop the execution of the function on the server.我不知道客户端内置超时的目的是什么,对我来说它没有任何目的,因为它甚至不会停止服务器上 function 的执行。 But it must be there for some internal reasons.但它一定存在于某些内部原因。

Notice the Node.js timeoutSeconds is in seconds and the timeout option on the client library is in milliseconds .请注意 Node.js timeoutSeconds为单位,客户端库上的超时选项以毫秒为单位

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM