Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js AWS lambda中的pg承诺_Node.js_Postgresql_Aws Lambda_Pg Promise - Fatal编程技术网

Node.js AWS lambda中的pg承诺

Node.js AWS lambda中的pg承诺,node.js,postgresql,aws-lambda,pg-promise,Node.js,Postgresql,Aws Lambda,Pg Promise,我在使用AWS lambda的pg promise时遇到了很多问题。我想了解如何解决这些问题 库建议您创建数据库对象的一个实例,然后将其从模块中导出。应该只创建一个对象实例。 比如: const db = pgp({ host: process.env.DATABASE_HOST, port: process.env.DATABASE_PORT, database: process.env.DATABASE_NAME, user: process.env.DATABASE_USE

我在使用AWS lambda的pg promise时遇到了很多问题。我想了解如何解决这些问题

库建议您创建数据库对象的一个实例,然后将其从模块中导出。应该只创建一个对象实例。 比如:

const db = pgp({
  host: process.env.DATABASE_HOST,
  port: process.env.DATABASE_PORT,
  database: process.env.DATABASE_NAME,
  user: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
  poolSize: 0,
  poolIdleTimeout: 10,
});
module.exports = db;
我知道这只是一个对象,这里没有创建连接。当您在此db对象上运行任何操作(如db.query())时,将延迟创建连接

由于我们将池大小设置为0,因此将只创建一个连接。这就是我们需要的,在每个lambda函数开始时,我们需要创建一个连接,然后在lambda完成时关闭连接

我们面临的问题是:

  • 我们如何释放连接? AWS lambdas可重复使用容器。这意味着它将调用已初始化的同一节点代码,并在前一次运行后不久调用lambda时重新运行同一函数。 这意味着db对象将与lambda的下一次调用相同。在第一个lambda完成后,如果调用pgp.end(),文档会说连接池将关闭。它还说,在那之后,我们不能在相同的过程中使用pgp库。但该库将被使用,因为db对象仍处于活动状态,并将在后续运行中使用

  • 如何重试获取新连接?
    AWS lambda带来的另一个问题是,当您在VPC内运行lambda,并且您的Postgres实例也在VPC内运行时,Postgres数据库的DNS需要时间才能解析。因此,如果您尝试连接,可能会出现ENOTFOUND错误。AWS的建议是重试获取连接。使用pg promise如何重试获取连接

  • 我想实施的方式是:

    module.exports.handler = (event, context, callback) => {
     let connection;
     try {
      connection = /*gets connection and retries if it failed the first time*/
      // run db queries and transactions.. etc.
      callback(null, result);
     } finally {
      connection.close();
     }
    
    }
    
    我们如何释放连接

    你没有。连接会自动与连接池通信。一旦查询结束执行,连接将返回到池中,以供下一个请求它的查询使用

    当一次执行多个查询时,应该使用任务。看

    如何重试获取新连接

    连接池根据连接需求和最大池大小,在必要时自动创建新的物理连接。当连接断开时,会自动重新创建连接


    如果AWS lambda中只有一个连接,那么最好的模式是创建和维护一个全局连接

    如果是这样的话,这个例子可能对你有用。它展示了如何在连接池之外维护单个全局连接,以及如何使其始终处于活动状态


    但这更像是最后的手段。我相信仅仅使用自动连接池就足够了。

    这就是我们最终要做的

    jist是在每个lambda开始之前创建一个新连接,然后在从lambda返回之前关闭它

    // your lambda entry point
    module.exports.handler = (event, context, callback) =>  
    getConnection(async (connection) => {
        let result;
        try {
            // work with your connection
        } catch (error) {
        }
        callback(null, result);
    })
    
    
    // db connection 
    
    const getConnection = async (callback) => {
    const dbConnection = new DBConnection();
    try {
        const connection = await dbConnection.create();
        await callback(connection);
    } finally {
        dbConnection.close();
    }
    };
    
    const MAX_RETRY = 3;
    
    const options = {
    // global event notification;
    error: (error, e) => {
        if (e.cn) {
        // A connection-related error;
        //
        // Connections are reported back with the password hashed,
        // for safe errors logging, without exposing passwords.
        logger.error('CN:', e.cn);
        logger.error('EVENT:', error.message || error);
        }
    },
    };
    
    const pgp = require('pg-promise')(options);
    
    const connectionParams = {
    host: process.env.DATABASE_HOST,
    port: process.env.DATABASE_PORT,
    database: process.env.DATABASE_NAME,
    user: process.env.DATABASE_USERNAME,
    password: process.env.DATABASE_PASSWORD,
    poolSize: 0,
    poolIdleTimeout: 10,
    };
    
    const db = pgp(connectionParams);
    
    class DBConnection {
    
    async create() {
        let retry = 0;
        while (retry < MAX_RETRY) {
        try {
            logger.debug(`Acquiring a new DB connection Attempt: ${retry}/${MAX_RETRY}`);
            this.connection = await db.connect({ direct: true });
            break;
        } catch (error) {
            logger.error(`Error occurred while getting DB connection ${error}. Retrying ${retry}/${MAX_RETRY}`);
            retry += 1;
        }
        }
    
        if (!this.connection) {
        throw Error(`Unable to obtain DB connection after ${MAX_RETRY} retries`);
        }
    
        return this.connection;
    }
    
    close() {
        if (this.connection) {
        logger.debug('Closing DB Connection');
        this.connection.done();
        }
    }
    }
    
    //您的lambda入口点
    module.exports.handler=(事件、上下文、回调)=>
    getConnection(异步(连接)=>{
    让结果;
    试一试{
    //使用您的连接
    }捕获(错误){
    }
    回调(null,result);
    })
    //数据库连接
    const getConnection=async(回调)=>{
    const dbConnection=new dbConnection();
    试一试{
    const connection=await dbConnection.create();
    等待回调(连接);
    }最后{
    dbConnection.close();
    }
    };
    const MAX_RETRY=3;
    常量选项={
    //全球事件通知;
    错误:(错误,e)=>{
    国际单项体育联合会(e.cn){
    //与连接相关的错误;
    //
    //连接被报告回来,密码被散列,
    //用于安全的错误记录,无需公开密码。
    logger.error('CN:',e.CN);
    logger.error('EVENT:',error.message | | error);
    }
    },
    };
    const pgp=要求(“pg-promise”)(选项);
    常量连接参数={
    主机:process.env.DATABASE\u主机,
    端口:process.env.DATABASE\u端口,
    数据库:process.env.database_NAME,
    用户:process.env.DATABASE_用户名,
    密码:process.env.DATABASE\u密码,
    池大小:0,
    poolIdleTimeout:10,
    };
    const db=pgp(connectionParams);
    类DBConnection{
    异步创建(){
    让重试=0;
    while(重试<最大重试次数){
    试一试{
    debug(`获取新的数据库连接尝试:${retry}/${MAX_retry}`);
    this.connection=await db.connect({direct:true});
    打破
    }捕获(错误){
    logger.error(`获取数据库连接时出错${error}。重试${retry}/${MAX_retry}`);
    重试+=1;
    }
    }
    如果(!this.connection){
    抛出错误(`在${MAX\u RETRY}重试之后无法获得数据库连接');
    }
    返回此连接;
    }
    关闭(){
    如果(此连接){
    debug('关闭数据库连接');
    this.connection.done();
    }
    }
    }
    
    谢谢你的回答。我应该在lambda调用结束时调用pgp.end()吗?在pgp.end()过程中到底发生了什么?跨lambda的不同调用共享连接时存在问题。这就是在lambda中使用连接池的问题。连接池中可能仍有连接。但在lambda完成后,节点进程处于“冻结”状态。这可能意味着lambda和db之间的套接字也可能已关闭。您的问题是否跨越多个Node.js进程有很好的记录;)我的主要问题是数据库的DNS解析。当我的lambda启动时,它尝试执行一个查询,库尝试获取一个连接,它还找不到它,因为DNS还没有复制。如果它在几秒钟内再次尝试连接,它将正常工作。我不知道如何使用连接池实现,如果我尝试使用单一的全局连接方法,我不知道如何使用transac