首页 > 解决方案 > 带有 Firebase 云函数错误的 SendGrid:“套接字挂起”

问题描述

我有一个由发布/订阅事件触发的云函数。我使用 sendgrid nodejs api。主要想法是向我的客户发送每周统计电子邮件。sendEmail() 函数为每个客户端运行(80 次)。但是当我检查功能日志时,我看到 25-30 封客户电子邮件发送成功,但其余的却给出了错误:“socket hang up”

我缩短了整个代码以显示与发送电子邮件相关的主要部分。这是最后一部分。

    // I shortened the whole function as it is a very long function.
    // The main and the last part is as below
    // I have nearly 80 clients and sendEmail function run for each client.

    function calcData(i, data) {
        return admin.database().ref('clientUrlClicks/' + data.key)
            .orderByChild('date')
            .startAt(dateStartEpox)
            .endAt(dateEndEpox)
            .once('value', urlClickSnap => {
                clients[i].clickTotalWeek = urlClickSnap.numChildren();
                clients[i].listTotalWeek = 0;
                admin.database().ref('clientImpressions/' + data.key)
                    .orderByKey()
                    .startAt(dateStart)
                    .endAt(dateEnd)
                    .once('value', snap => {
                        snap.forEach(function(impressionSnap) {
                            clients[i].listTotalWeek += impressionSnap.val();
                        })
                    }).then(resp => {
                        return sendEmail(i, clients[i]);
                    }).catch(err => {
                        console.log(err);
                    });
            }).catch(err => {
                clients[i].clickTotalWeek = 0;
                console.log(err);
            });
    }

   function sendEmail(i, data) {
        var options = {
            method: 'POST',
            url: 'https://api.sendgrid.com/v3/mail/send',
            headers:
            {
                'content-type': 'application/json',
                authorization: 'Bearer ' + sgApiKey
            },
            body:
            {
                personalizations:
                    [{
                        to: [{ email: data.email, name: data.name }],
                        dynamic_template_data:
                        {
                            dateStart: xxx,
                            dateEnd: xxx,
                        }
                    }],
                from: { email: 'info@xxx.com', name: 'xxx' },
                reply_to: { email: 'info@xxx.com', name: 'xxx' },
                template_id: 'd-f44eeexxxxxxxxxxxxx'
            },
            json: true
        };

        request(options, function (error, response, body) {
            if (error) {
                console.log("err: " + error);
                return;
            }
            return;
        });
    }

编辑:

除了以下与“正确链接承诺”相关的答案之外,我还将所有电子邮件和个性化添加到“个性化”数组作为“sendEmail”函数的对象。因此,我对每封电子邮件提出一个请求,而不是提出一个请求。现在没问题。

标签: firebasegoogle-cloud-functionssendgrid-api-v3

解决方案


您没有正确链接承诺,因此没有在链接结束时返回最终承诺,这对于云函数是强制性的。

下面的一组修改是解决这个问题的第一次尝试。

此外,您如何调用 Sendgrid 并返回 Sendgrid 调用返回的 Promise 也不是很清楚。我建议您使用send()返回 Promise 的方法,如适用于 Node.js 的 Sendgrid v3 Web API 文档中所述,请参阅https://github.com/sendgrid/sendgrid-nodejs/tree/master/packages /邮件

function calcData(i, data) {
        //Declare clients aray here
        return admin.database().ref('clientUrlClicks/' + data.key)
            .orderByChild('date')
            .startAt(dateStartEpox)
            .endAt(dateEndEpox)
            .once('value')
            .then(urlClickSnap => {
                clients[i].clickTotalWeek = urlClickSnap.numChildren();
                clients[i].listTotalWeek = 0;
                return admin.database().ref('clientImpressions/' + data.key)  //Here you didn't return the promise
                    .orderByKey()
                    .startAt(dateStart)
                    .endAt(dateEnd)
                    .once('value');
             .then(snap => {
                     snap.forEach(function(impressionSnap) {
                         clients[i].listTotalWeek += impressionSnap.val();
                    })
                    return sendEmail(i, clients[i]);
             }).catch(err => {
                clients[i].clickTotalWeek = 0;
                console.log(err);
                return null;
            });
    }

推荐阅读