【问题标题】:NodeJS / Express function only invoked one time in Google Cloud functionsNodeJS / Express 函数仅在 Google Cloud 函数中调用一次
【发布时间】:2020-06-07 10:48:49
【问题描述】:

我正在创建一个谷歌云功能,该功能每天向用户发送一封电子邮件,但该功能仅在部署后第一次调用,然后即使在 300 秒后也总是因超时而失败(通常需要 10 - 15 秒才能执行) .

该函数正在执行 DB 查找、for 循环和 if 条件,所以我认为这是来自应用程序的请求/响应问题,因此它会阻止将来调用。你能帮我修改下面的代码吗?

app.get('/emails', function(req, res){
    var books = [];
    Book.find({}, (err, res) => {
       if (err) {
           return err;
       }
       books = res;
   }).catch(err => console.log(err))
   User.find({}, (err, users) => {
    if (err) {
        return err;
    }

    const uniques = users.filter(
      (v, i, a) => a.findIndex((t) => t.ID === v.ID) === i
    );

    for(var i =0; i < uniques.length; i++) {
      var count = 0;
      for (var j = 0; j < books.length; j++) {
        if (books[j].UserID === uniques[i].ID && books[j].State === "OK") {
          count += 1;
        }
      }
      var EmailPayload = {
          // nodemailer object here
    }
    if (count > 0) {
      Email.sendEmailIndex(EmailPayload);
    }
    } 
  }).catch(err => {
    console.log(err)
  })
  });

【问题讨论】:

  • 如果您添加了console.log 语句并包含执行日志以了解停止执行的位置,这将非常有用。
  • 函数究竟是如何触发的?
  • 它是由HTTP调用GET /cloud/emails触发的,部署后第一次调用然后日志总是说超时

标签: node.js express google-cloud-platform google-cloud-functions timeout


【解决方案1】:

该函数被 GET /emails 调用,它期望得到响应。如果没有响应,该函数将继续运行,直到超时,因为 Google 不知道它已完成。

要解决此问题,请在脚本完成后以基本 200 结束。在未能涵盖所有情况的情况下做出响应并确保始终有响应发回也是明智的。

app.get('/emails', function(req, res) {
    var books = [];
    Book.find({}, (err, res) => {
        if (err) {
            return err;
        }
        books = res;

        return User.find({}, (err, users) => {
            if (err) {
                return err;
            }

            const uniques = users.filter(
                (v, i, a) => a.findIndex((t) => t.ID === v.ID) === i
            );

            for (var i = 0; i < uniques.length; i++) {
                var count = 0;
                for (var j = 0; j < books.length; j++) {
                    if (books[j].UserID === uniques[i].ID && books[j].State === "OK") {
                        count += 1;
                    }
                }
                var EmailPayload = {
                    // nodemailer object here
                }
                if (count > 0) {
                    Email.sendEmailIndex(EmailPayload);
                }
            }

            // Send a response to conclude function execution
            res.status(200).send({
                message: 'Emails sent'
            });
        });
    }).catch(err => {
        console.log(err);

        // Send a response to conclude function execution
        res.status(500).send({
            message: 'Failed to send emails',
            error: err
        });
    })
});

【讨论】:

  • 嗨,当我调用 GET 时,它直接发送 {"message":"Emails sent"} ,我尝试在消息前添加一些时间: res.setTimeout(15000, function(){ res .status(200).send({ message: 'Emails sent' }); }) 等待 15 秒但不发送邮件。
  • 我必须将 User.find() 中的所有代码放入 Book.find() 结果中。现在可以使用了!
  • 啊,是的,有道理!使用 Promise 的棘手部分:)。我已经更新了答案以反映您的所作所为。因为我们把 User.find() 放在 Book.find() 里面,我们也可以去掉 User.find() 的 .catch() 子句。我们返回将在最后一个 .catch 子句中执行的 User.find() 的结果。我建议学习 async/await,这样你就可以编写更简单、更容易理解的 Promise
猜你喜欢
  • 2021-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-05
  • 2021-03-20
  • 1970-01-01
相关资源
最近更新 更多