Node.js AWS lambda中的pg承诺
我在使用AWS lambda的pg promise时遇到了很多问题。我想了解如何解决这些问题 库建议您创建数据库对象的一个实例,然后将其从模块中导出。应该只创建一个对象实例。 比如: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
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 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