【问题标题】:Lambda + DynamoDB + API gateway - Loop and execute results before returningLambda + DynamoDB + API gateway - 在返回之前循环并执行结果
【发布时间】:2020-06-29 20:18:00
【问题描述】:

我正在尝试创建一个 lambda API 调用,它将遍历 DynamoDB 表的结果并对 3rd 方系统执行不同的 API 调用。

扫描功能正常运行,因为它返回了正确的数据。

我在这里遇到了迭代问题,因为它不会触发对 Linkedin 的 Axios 调用,但是,该函数被称为 console.log bid 它会显示在云手表中。

云手表没有显示任何错误。

理想情况下,当完成并添加一个 API 调用 + 修改 dynamo DB 后,下面的功能将类似于一个 cron 作业,它会在一小时内每 x 次触发一次。

如果有人能建议我如何处理这个问题/提出不同的方法,我将不胜感激。

const dynamodb = require("aws-sdk/clients/dynamodb");
const axios = require("axios");
const docClient = new dynamodb.DocumentClient();

const tableName = "**************";

exports.executeJobs = async(event) => {
    const { httpMethod, path } = event;
    if (httpMethod !== "GET") {
        throw new Error(
            `Method only accepts GET method, you tried: ${httpMethod} method.`
        );
    }

    console.log("received:", JSON.stringify(event));

    var params = {
        TableName: tableName,
        ProjectionExpression: "#timestamper, #userId,#campaignId, #type,#info,#token",
        FilterExpression: "#timestamper < :timestamper",
        ExpressionAttributeNames: {
            "#timestamper": "timestamper",
            "#type": "type",
            "#info": "info",
            "#userId": "userId",
            "#campaignId": "campaignId",
            "#token": "token",
        },
        ExpressionAttributeValues: {
            ":timestamper": Date.now(),
        },
    };

    console.log("Scanning Jobs table."); 
    
    
      let scanResults = [];
    let items;

    do {
        items = await docClient.scan(params).promise();
        items.Items.forEach(async function (item) { 
            scanResults.push(item)
            
            try { 
    const response = await bidIt(item.campaignId, item.info.currency, item.token, item.info.bid);
    console.log(response);
  } catch (error) {
    console.error(error);
  }
            
        });
        params.ExclusiveStartKey = items.LastEvaluatedKey;
    } while (typeof items.LastEvaluatedKey != "undefined");
     
 
      const response = {
            statusCode: 200,
            body: JSON.stringify(scanResults),
        };

        console.log(
            `response from: ${path} statusCode: ${response.statusCode} body: ${response.body}`
        );
        return response;
};
 
  
    async function bidIt(campaignId, currency, token, bid) {
        console.log("bidIT");
        try {
            axios
                .post(
                    "https://api.linkedin.com/v2/adCampaignsV2/" + campaignId, {
                        patch: {
                            $set: {
                                unitCost: {
                                    amount: bid,
                                    currencyCode: currency,
                                },
                            },
                        },
                    }, {
                        headers: {
                            "Content-Type": "application/json",
                            "X-RestLi-Method": "PARTIAL_UPDATE",
                            Authorization: "Bearer " + token,
                        },
                    }
                )
                .then((result) => {
                     
                    return UpdateCpc(campaignId, currency, token, bid);
                });
        } catch (error) {
            console.log("error", error);
            // appropriately handle the error
        }
    }

更新: 谢谢,Kalev 的回复,我已经修改了代码,但是仍然没有等待 API 调用并关闭查询。 截图来自云手表。 (我将 bidIt 改为 getMinBid 名称)

async function getMinBid(campaignId, currency, token, bid) {
    try {
        console.log("getMinBid");
        let result = await axios.post(
                "https://api.linkedin.com/v2/adCampaignsV2/" + campaignId, {
                    patch: {
                        $set: {
                            unitCost: {
                                amount: bid,
                                currencyCode: currency,
                            },
                        },
                    },
                }, {
                    headers: {
                        "Content-Type": "application/json",
                        "X-RestLi-Method": "PARTIAL_UPDATE",
                        Authorization: "Bearer " + token,
                    },
                }
            )
            .then((result) => {
                console.log("axios success");
                console.log(JSON.stringify(result));
                let minCost = result.data.split("lower than ").pop();
                minCost = parseFloat(minCost) + bid; 
            });
          return UpdateCpc(campaignId, currency, token, minCost);
    } catch (error) {
        console.log('test bid')
        console.log("error", error);
        // appropriately handle the error
    }
}

【问题讨论】:

    标签: node.js amazon-web-services aws-lambda axios amazon-dynamodb


    【解决方案1】:

    原答案

    您的问题在于 bidIt 中对 axios.post 的异步调用。该调用产生了一个承诺,但你没有在承诺上await,也没有返回承诺,所以函数返回undefined

    注意return UpdateCpc 是在promise 的then 处理程序中创建的。它不会从bidIt 调用中返回(我假设您在那里尝试这样做)。

    使用 async/await,您可以执行以下操作:

    async function bidIt(campaignId, currency, token, bid) {
        try {
            result = await axios.post(<parameters>));
            return UpdateCpc(campaignId, currency, token, bid);
        } catch (error) { ... }
    }
    

    使用 Promise,你可以做以下事情:(这种风格有点多余,但有些人可能更喜欢它)

    async function bidIt(campaignId, currency, token, bid) {
        return axios.post(<parameters>))
                    .then((result) => UpdateCpc(campaignId, currency, token, bid))
                    .catch((err) => { ... });
    }
    

    更新

    我最初错过了调用bidIt的部分代码中的问题。那里也没有正确处理异步调用。

    在您的循环中,await 在 Promise 处理程序中完成,但其余代码继续并终止。

    具体来说,您从 foreach 调用中调用了一个异步函数。所有这些函数都是异步运行的,但你没有await 它们,你也没有将它们作为承诺返回。

    这是您当前的 do-while 循环,已简化:

    do {
        items = await docClient.scan(params).promise();
        items.Items
             .forEach(async function (item) { 
                          scanResults.push(item)
                          try { 
                              const response = await bidIt(<parameters>);
                          } catch (error) { ... }
                      });
        params.ExclusiveStartKey = items.LastEvaluatedKey;
    } while (typeof items.LastEvaluatedKey != "undefined");
    

    注意await bidIt 调用如何在从items.Items.forEach 调用的异步函数的范围内。对items.Items.forEach 的调用本身会创建一堆异步调用,并在异步调用有机会完成之前继续执行

    修复

    使用 async/await,您可以通过以下方式修复循环:

    do {
        items = await docClient.scan(params).promise();
        for (item of items.Items) {
            scanResults.push(item)
            try { 
                const response = await bidIt(<parameters>);
            } catch (error) { ... }
        }
        params.ExclusiveStartKey = items.LastEvaluatedKey;
    } while (typeof items.LastEvaluatedKey != "undefined");
    

    同样可以使用 Promise 来实现,但需要收集所有产生的 Promise,然后返回一个组合的 Promise,方法是对代码产生的 Promise 集执行 Promise.all(...)。它需要一些细微差别,并且需要更改的不仅仅是 do-while 循环,所以我在这里省略了代码。这并不复杂,但你需要小心不要失去任何承诺。

    【讨论】:

    • 我已经应用了你的解决方案,但是 axios 仍然没有触发。
    • 我已将修复添加到代码中以更新我的答案。异步编程有时会很棘手。你应该注意你的调用范围,以及你是否await所有的异步调用。一般来说,当异步调用似乎没有运行时,这通常是问题所在。
    • 那是伟大的 Kalev,你是救生员。它正在工作我只是从bidIt函数内部去console.log输出。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2018-11-06
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    • 1970-01-01
    • 2017-04-19
    • 1970-01-01
    相关资源
    最近更新 更多