You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Lambda无法执行多顺序Node.js函数问题求助

AWS Lambda 多顺序函数执行问题修复

我正尝试将index.js文件部署到AWS Lambda,实现每日凌晨自动执行。已完成文件上传操作,但代码在Lambda环境中无法按顺序执行多个函数:本地执行node index.js一切正常,但Lambda测试时仅第一个getToken函数触发。需要调整代码,确保先获取API访问令牌,再用令牌更新DynamoDB表。

原代码:

var AWS = require('aws-sdk');
AWS.config.update({region: 'us-west-2'});


async function getToken (event, context) {

    artistRank = 0;
    console.log("GETTING TOKEN...")
  
    getToken = await fetch("https://api.chartmetric.com/api/token", {
        body: '{"refreshtoken":"*************************************"}',
        headers: {
          "Content-Type": "application/json"
        },
        method: "POST"
      })
      .then( res => res.json() )
      .then( data => {
        
        token = data.token;
        console.log(token)
        readTable(token);

})};

async function readTable (token) {

    // Create the DynamoDB service object
    var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

    for (let i = 0; i < 50; i++) {

        setTimeout(() => {

            var params = {
            TableName: 'popularCharts',
            Key: {
                'rank': {N: String(i)}
            },
            ProjectionExpression: 'currentRank, id'
            };

            ddb.getItem(params, function (err, data) {
                if (err) {
                    console.log("Error", err);
                } else {
                    artistId = data['Item'].id
                    idString = JSON.stringify(artistId);
                    idLength = idString.length;
                    idFinal = idString.slice(6, idLength - 2);
                
                    pointsScored(token, idFinal, i)
                }
            });

        }, i*2000);
    }


}


async function pointsScored (accessKey, id, rank) {

    fetch("https://api.chartmetric.com/api/artist/" + id + "/cpp?stat=score", {
        headers: {
            Authorization: "Bearer " + String(accessKey)
        }
    })
        .then( res => res.json() )
        .then( data => {

            length = data['obj'].length;

            change = (data['obj'][length-1].score - data['obj'][length-4].score)*1000000;

            console.log(change)

            var ddb2 = new AWS.DynamoDB({apiVersion: '2012-08-10'});
          
            var params2 = {
                TableName: 'pointsScored',
                Item: {
                  'rank' : {N: String(rank)},
                  'id' : {N: String(id)},
                  'playlistPoints' : {S: String(change)},
                  'currentRank' : {N: String(rank)}
                }
            }
            ddb2.putItem(params2, function(err, data) {
                if (err) {
                    console.log("Error", err);}
            });
        })

}

exports.handler = getToken();

问题根源及修复方案

1. Lambda Handler配置错误

原代码直接调用getToken()并赋值给exports.handler,会在代码加载时立即执行函数,而非由Lambda触发时执行。正确做法是导出函数本身,且需确保handler等待所有异步操作完成,避免Lambda提前终止。

2. 未处理异步操作的等待

Lambda会在事件循环为空时终止执行,原代码中readTable和pointsScored里的setTimeout、回调式DynamoDB操作都是异步的,未被等待,导致Lambda在这些操作完成前就结束了。

3. 全局变量风险

代码中使用了artistRank、token等未声明的全局变量,易引发意外的变量污染和逻辑错误,需改为局部变量并使用let/const声明。

4. Await与回调混用

getToken中同时使用await和.then(),逻辑混乱,应统一使用await处理异步操作。


修正后的完整代码

const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-west-2' });

// 工具函数:实现延迟
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function getToken(event, context) {
    let artistRank = 0;
    console.log("GETTING TOKEN...");
  
    const tokenResponse = await fetch("https://api.chartmetric.com/api/token", {
        body: '{"refreshtoken":"*************************************"}',
        headers: {
          "Content-Type": "application/json"
        },
        method: "POST"
    });
    const data = await tokenResponse.json();
    const token = data.token;
    console.log(token);
    
    // 等待readTable完成所有操作
    await readTable(token);
}

async function readTable(token) {
    const ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });

    // 改用异步循环,确保每个请求完成后再进行下一个,同时遵守速率限制
    for (let i = 0; i < 50; i++) {
        const params = {
            TableName: 'popularCharts',
            Key: {
                'rank': { N: String(i) }
            },
            ProjectionExpression: 'currentRank, id'
        };

        try {
            const data = await ddb.getItem(params).promise();
            const artistId = data.Item.id;
            // 简化ID提取逻辑
            const idFinal = artistId.N; // 直接获取DynamoDB数字类型的原始值
            
            // 等待pointsScored完成
            await pointsScored(token, idFinal, i);
        } catch (err) {
            console.log("Error reading item:", err);
        }

        // 每次请求后延迟2秒,避免API限流
        if (i < 49) {
            await delay(2000);
        }
    }
}

async function pointsScored(accessKey, id, rank) {
    const response = await fetch(`https://api.chartmetric.com/api/artist/${id}/cpp?stat=score`, {
        headers: {
            Authorization: `Bearer ${accessKey}`
        }
    });
    const data = await response.json();
    
    const length = data.obj.length;
    const change = (data.obj[length - 1].score - data.obj[length - 4].score) * 1000000;
    console.log(`Rank ${rank} change: ${change}`);

    const ddb2 = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
    const params2 = {
        TableName: 'pointsScored',
        Item: {
            'rank': { N: String(rank) },
            'id': { N: id },
            'playlistPoints': { S: String(change) },
            'currentRank': { N: String(rank) }
        }
    };

    try {
        await ddb2.putItem(params2).promise();
    } catch (err) {
        console.log("Error putting item:", err);
    }
}

// 正确导出Lambda handler
exports.handler = getToken;

关键修正说明

  1. Handler修正:直接导出getToken函数,Lambda会在触发时传入event和context参数,且getToken是异步函数,会等待后续所有操作完成。
  2. 统一使用Await:所有异步操作(fetch、DynamoDB调用)都改用await处理,确保执行顺序和完成等待。
  3. 全局变量替换:所有变量改为局部变量,用let/const声明,避免污染。
  4. 简化ID提取:直接从DynamoDB返回的Item中获取id.N,无需JSON.stringify后截取字符串。
  5. 异步循环:将原setTimeout循环改为带延迟的异步循环,确保每个请求依次执行,同时避免API限流。
  6. 错误处理:添加try/catch捕获异步操作中的错误,便于排查问题。

内容的提问来源于stack exchange,提问作者Jack Eggert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:07:29