Node.js AWS Lambda 没有等待任何东西

Node.js AWS Lambda not waiting for anything

我已经尝试了所有建议的解决方案并查看了每个类似的问题,但没有解决我的问题。这个脚本在我的本地机器上工作得很好。 Lambda 的问题在于它完全跳过超时和等待。而我的本地机器实际上在等待。

我的索引文件如下所示:

import { getData } from './src/EC2Scripts/taskScripts/otherLogic.js';

async function handler(event) {
        await getData();
        
        const response = {
            statusCode: 200,
            body: JSON.stringify("Not waiting."),
        };

        return response;
}

export { handler };

这是其他逻辑 class:

import fetch from "node-fetch";
import { PoolConnection } from '../common/classes/PoolConnection.js';

async function getData() {
    return new Promise(async (resolve, reject) => {
       let pool = PoolConnection.getInstance();
       let currentResponse = await fetch(
            "dummyURL"
       );
        
       let currentData = await currentResponse.json();
        
       pool.uploadCoins(currentData).then((result) => { 
            pool.endConnection().then((end) => { resolve() }); 
       });
    });
}

export { getData };

这是 PoolConnection class:

import pg from "pg";
import fetch from "node-fetch";

import { getCurrentDateTime } from "../dateTime.js";

class PoolConnection {
    // DO NOT CALL THIS CONSTRUCTOR, CALL THE GETINSTANCE() METHOD
    constructor() {
        if (!PoolConnection.instance) {
            PoolConnection.instance = this;

            this.config = {
                user: "user",
                password: "password",
                database: "postgres",
                host: "host",
                port: 5432,
                max: 100,
                connectionTimeoutMillis: 30000,
                idleTimeoutMillis: 30000
            };
            this.pool = this.establishConnection(1).catch((error) => { });
        }
    }

    static getInstance() {
        if (PoolConnection.instance) {
            return PoolConnection.instance;
        }

        PoolConnection.instance = new PoolConnection();
        return PoolConnection.instance;
    }

    async connect() {
        return new Promise((resolve, reject) => {
            const poolPromise = new pg.Pool(this.config);
            poolPromise.connect()
                .then(pool => {
                    console.log(getCurrentDateTime() + " ----- Connection to article database successful.");
                    resolve(pool);
                })
                .catch(err => {
                    console.error(getCurrentDateTime() + " ----- ERROR CONNECTING TO ARTICLE DATABASE :: " + err);
                    reject(err);
                });
        });
    }

    async establishConnection(attempts) {
        return new Promise((resolve, reject) => {
            if (attempts > 5) {
                console.log(getCurrentDateTime() + " ---- Connection unsuccessful to database, maximum number of attempts reached.");
                reject("ERROR");
            }

            this.connect().then(pool => {
                resolve(pool);
            }).catch(err => {
                console.error(getCurrentDateTime() + " RETRYING CONNECTION TO DATABASE ATTEMPT #" + attempts);
                attempts++;
                // try again in 3 seconds
                setTimeout(() => { this.establishConnection(attempts) }, 3000);
            });
        })
    }

    //  Connection has to be terminated gracefully or else script will hang.
    async endConnection() {
        return new Promise((resolve, reject) => {
           this.pool.then(connection => connection.end(() => console.log(getCurrentDateTime() + " ---- Connection to database successfully terminated."))); 
        });
    }

    async uploadData(data) {
        return new Promise((resolve, reject) => {
           this.pool.then(async (poolInstance) => {
                for(const entry of data) {
                    
                    let getMoreData = await fetch (
                        "dummyUrl2" + entry
                    );
    
                    const result = poolInstance.query("INSERT INTO table(data) VALUES ()", 
                                                    [entry['getMoreData']]);
                }
                resolve();
            }); 
        });
    }
}

export { PoolConnection }

它试图在我做任何事情之前关闭连接。这是错误:

> START RequestId: 5aa4984b-d57f-4d69-84a3-005a6c590c0f Version: $LATEST
> 2022-05-03T14:48:11.625Z  5aa4984b-d57f-4d69-84a3-005a6c590c0f    INFO    2022-5-3
> **** 14:48:11 ----- Connection to article database successful. 2022-05-03T14:48:12.946Z   5aa4984b-d57f-4d69-84a3-005a6c590c0f    INFO    2022-5-3
> **** 14:48:12 ---- Connection to database successfully terminated. 2022-05-03T14:48:14.146Z   5aa4984b-d57f-4d69-84a3-005a6c590c0f    ERROR   Unhandled Promise Rejection
>   {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"Error:
> Client was closed and is not
> queryable","reason":{"errorType":"Error","errorMessage":"Client was
> closed and is not queryable","stack":["Error: Client was closed and is
> not queryable","    at
> /var/task/node_modules/pg/lib/client.js:570:27","    at
> processTicksAndRejections
> (internal/process/task_queues.js:77:11)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection:
> Error: Client was closed and is not queryable","    at
> process.<anonymous> (/var/runtime/index.js:35:15)","    at
> process.emit (events.js:400:28)","    at processPromiseRejections
> (internal/process/promises.js:245:33)","    at
> processTicksAndRejections (internal/process/task_queues.js:96:32)"]}
> END RequestId: 5aa4984b-d57f-4d69-84a3-005a6c590c0f REPORT RequestId:
> 5aa4984b-d57f-4d69-84a3-005a6c590c0f  Duration: 2985.31 ms    Billed
> Duration: 2986 ms Memory Size: 128 MB Max Memory Used: 75 MB  Init
> Duration: 267.75 ms

我已经尝试将所有内容转换为 return 一个新的 Promise,然后使用 .then(),但这实际上使程序 运行 不知何故变得更快。我试过使用 Promise.all().then()。我试过将 setTimeout() 移动到 index.js 中的处理程序中,但这也没有用。我试过在 pool.uploadData() 之后使用 then()。我也试过从方法处理程序中删除异步。

我现在没主意了。我已经重构并尝试以我见过的所有方式实现此代码,但没有任何效果。

没有错误或未捕获的异常,只是没有等待。

Lambda 使用的是 NodeJS 版本 14.x

编辑:添加池连接 class 并更新 classes 以更清楚地显示我尝试过的内容。

虽然 getData() 被标记为 async,但它没有 return 任何明确的承诺,因此它 return 是一个 Promise<void> 立即解析(到undefined)。

您需要 return 一个明确的 Promise resolves/rejects 在您的业务逻辑 运行 之后,使 Lambda 实际上等待处理完成。

根据Node.js Lambda docs on async handlers

If your code performs an asynchronous task, return a promise to make sure that it finishes running. When you resolve or reject the promise, Lambda sends the response or error to the invoker.

例如,此 returns 是一个 Promise,它在 5 秒后解析,让 Lambda 在它 returns 响应之前等待:

async function getData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(), 5000)
    });
}

async function handler(event) {
    await getData();

    const response = {
        statusCode: 200,
        body: JSON.stringify("Waiting 5 seconds..."),
    };

    return response;
}

export { handler };
START RequestId: 0ee7693e-8d6a-4c3f-b23e-119377e633e3 Version: $LATEST
END RequestId: 0ee7693e-8d6a-4c3f-b23e-119377e633e3
REPORT RequestId: 0ee7693e-8d6a-4c3f-b23e-119377e633e3  Duration: 5009.05 ms    Billed Duration: 5010 ms    Memory Size: 128 MB Max Memory Used: 56 MB  Init Duration: 224.62 ms

我添加这个是因为我能够找出问题所在。在之前 answers/comments 的帮助下,我重新格式化了我的代码,因此如果其他人遇到类似问题,希望这会有所帮助。

index.js:

import { getData } from './src/EC2Scripts/taskScripts/otherLogic.js';

async function handler(event) {
        await getData();
        
        const response = {
            statusCode: 200,
            body: JSON.stringify("Now waiting."),
        };

        return response;
}

export { handler };

其他逻辑class:

import fetch from "node-fetch";
import { PoolConnection } from '../common/classes/PoolConnection.js';

async function getData() {
    return new Promise(async (resolve, reject) => {
       let pool = await PoolConnection.getInstance();
       let currentResponse = await fetch(
            "dummyURL"
       );
        
       let currentData = await currentResponse.json();
       await pool.uploadData(currentData);
       await pool.endConnection();
       resolve();
    });
}

export { getData };

池连接class:

import pg from "pg";
import fetch from "node-fetch";

import { getCurrentDateTime } from "../dateTime.js";

class PoolConnection {
    // DO NOT CALL THIS CONSTRUCTOR, CALL THE GETINSTANCE() METHOD
    constructor() {
        if (!PoolConnection.instance) {
            PoolConnection.instance = this;

            this.config = {
                user: "user",
                password: "password",
                database: "postgres",
                host: "host",
                port: 5432,
                max: 100,
                connectionTimeoutMillis: 30000,
                idleTimeoutMillis: 30000
            };

            this.pool = new pg.Pool(this.config);
        }
    }

    static async getInstance() {
        return new Promise(async (resolve, reject) => {
            if (PoolConnection.instance) {
                return PoolConnection.instance;
            }

            PoolConnection.instance = new PoolConnection();
            resolve(PoolConnection.instance);
        });
    }

    //  Connection has to be terminated gracefully or else script will hang.
    async endConnection() {
        return new Promise(async (resolve, reject) => {
            await this.pool.end(() => console.log(getCurrentDateTime() + " ---- Connection to database successfully terminated."));
            resolve();
        });
    }

    async uploadData(data) {
        return new Promise(async (resolve) => {
            let promiseArray = [];

            for (const entry of data) {
                promiseArray.push(new Promise(async (resolve) => {
                    await this.pool.connect(async (error, client, release) => {
                        if (error) {
                            console.error(getCurrentDateTime() + " ----- Error getting client. Error :: ", error.stack);
                        }
                        await client.query("query", (error, result, release) => {
                                release();
                                if (error) {
                                    console.error(getCurrentDateTime() + " ----- Error executing query :: ", error.stack);
                                }
                                resolve();
                         });
                    });
                }));
            }
            await Promise.all(promiseArray);
            resolve();
        });
    }
}

export { PoolConnection }

如果这不能解决您的问题,找到修复的两个最大帮助是 and