为什么使用 pg-promise 的 AWS Lambda 执行时间很长
Why AWS Lambda execution time is long using pg-promise
我开始使用 AWS Lambda 执行一项非常简单的任务,即执行 SQL 查询以从 RDS postgres 数据库检索记录并根据结果创建 SQS 消息。
因为亚马逊默认只提供 aws-sdk
模块(使用节点 4.3 引擎),我们需要执行这个 SQL 查询,我们必须创建一个自定义部署包,其中包括 pg-promise
.这是我正在使用的代码:
console.info('Loading the modules...');
var aws = require('aws-sdk');
var sqs = new aws.SQS();
var config = {
db: {
username: '[DB_USERNAME]',
password: '[DB_PASSWORD]',
host: '[DB_HOST]',
port: '[DB_PORT]',
database: '[DB_NAME]'
}
};
var pgp = require('pg-promise')({});
var cn = `postgres://${config.db.username}:${config.db.password}@${config.db.host}:${config.db.port}/${config.db.database}`;
if (!db) {
console.info('Connecting to the database...');
var db = pgp(cn);
} else {
console.info('Re-use database connection...');
}
console.log('loading the lambda function...');
exports.handler = function(event, context, callback) {
var now = new Date();
console.log('Current time: ' + now.toISOString());
// Select auction that need to updated
var query = [
'SELECT *',
'FROM "users"',
'WHERE "users"."registrationDate"<=${now}',
'AND "users"."status"=1',
].join(' ');
console.info('Executing SQL query: ' + query);
db.many(query, { status: 2, now: now.toISOString() }).then(function(data) {
var ids = [];
data.forEach(function(auction) {
ids.push(auction.id);
});
if (ids.length == 0) {
callback(null, 'No user to update');
} else {
var sqsMessage = {
MessageBody: JSON.stringify({ action: 'USERS_UPDATE', data: ids}), /* required */
QueueUrl: '[SQS_USER_QUEUE]', /* required */
};
console.log('Sending SQS Message...', sqsMessage);
sqs.sendMessage(sqsMessage, function(err, sqsResponse) {
console.info('SQS message sent!');
if (err) {
callback(err);
} else {
callback(null, ids.length + ' users were affected. SQS Message created:' + sqsResponse.MessageId);
}
});
}
}).catch(function(error) {
callback(error);
});
};
在测试我的 lambda 函数时,如果您查看 WatchLogs,该函数本身花费了大约 500 毫秒到 运行,但它说它实际上花费了 30502.48 毫秒(参见屏幕截图)。
所以我猜解压我的 318KB 包并开始执行它需要 30 秒?那对我来说只是个玩笑还是我错过了什么?我尝试上传 zip 并将我的包上传到 S3 以检查它是否更快,但我仍然有相同的延迟。
我注意到 Python 版本可以本机执行 SQL 请求而无需任何自定义包装...
我们所有的应用程序都是用 node 编写的,所以我真的不想离开它,但是我很难理解为什么亚马逊不提供用于数据库交互的基本 npm 模块。
欢迎任何意见或帮助。在这一点上,我不确定如果 Lambda 需要 30 秒才能 运行 每分钟触发一个脚本...
有人遇到同样的问题吗?
更新:这就是您需要在不再需要时立即关闭连接的方式(再次感谢 Vitaly 的帮助):
exports.handler = function(event, context, callback) {
[...]
db.many(query, { status: 2, now: now.toISOString() }).then(function(data) {
pgp.end(); // <-- This is important to close the connection directly after the request
[...]
执行时间应根据正在执行的操作的长度来衡量,而不是应用程序退出所需的时间。
有许多库以一种或另一种形式使用连接池。这些通常会在一段可配置的不活动时间后终止。
如果是pg-promise, which in turn uses node-postgres, such period of inactivity is determined by parameter poolIdleTimeout, which defaults to 30 seconds. With pg-promise,您可以通过pgp.pg.defaults.poolIdleTimeout
访问它。
如果您希望您的进程在执行完最后一个查询后退出,您需要通过调用 pgp.end()
来关闭连接池。有关详细信息,请参阅第 Library de-initialization 章。
在大多数code examples中也有显示,因为那些需要在完成后立即退出。
我开始使用 AWS Lambda 执行一项非常简单的任务,即执行 SQL 查询以从 RDS postgres 数据库检索记录并根据结果创建 SQS 消息。
因为亚马逊默认只提供 aws-sdk
模块(使用节点 4.3 引擎),我们需要执行这个 SQL 查询,我们必须创建一个自定义部署包,其中包括 pg-promise
.这是我正在使用的代码:
console.info('Loading the modules...');
var aws = require('aws-sdk');
var sqs = new aws.SQS();
var config = {
db: {
username: '[DB_USERNAME]',
password: '[DB_PASSWORD]',
host: '[DB_HOST]',
port: '[DB_PORT]',
database: '[DB_NAME]'
}
};
var pgp = require('pg-promise')({});
var cn = `postgres://${config.db.username}:${config.db.password}@${config.db.host}:${config.db.port}/${config.db.database}`;
if (!db) {
console.info('Connecting to the database...');
var db = pgp(cn);
} else {
console.info('Re-use database connection...');
}
console.log('loading the lambda function...');
exports.handler = function(event, context, callback) {
var now = new Date();
console.log('Current time: ' + now.toISOString());
// Select auction that need to updated
var query = [
'SELECT *',
'FROM "users"',
'WHERE "users"."registrationDate"<=${now}',
'AND "users"."status"=1',
].join(' ');
console.info('Executing SQL query: ' + query);
db.many(query, { status: 2, now: now.toISOString() }).then(function(data) {
var ids = [];
data.forEach(function(auction) {
ids.push(auction.id);
});
if (ids.length == 0) {
callback(null, 'No user to update');
} else {
var sqsMessage = {
MessageBody: JSON.stringify({ action: 'USERS_UPDATE', data: ids}), /* required */
QueueUrl: '[SQS_USER_QUEUE]', /* required */
};
console.log('Sending SQS Message...', sqsMessage);
sqs.sendMessage(sqsMessage, function(err, sqsResponse) {
console.info('SQS message sent!');
if (err) {
callback(err);
} else {
callback(null, ids.length + ' users were affected. SQS Message created:' + sqsResponse.MessageId);
}
});
}
}).catch(function(error) {
callback(error);
});
};
在测试我的 lambda 函数时,如果您查看 WatchLogs,该函数本身花费了大约 500 毫秒到 运行,但它说它实际上花费了 30502.48 毫秒(参见屏幕截图)。
所以我猜解压我的 318KB 包并开始执行它需要 30 秒?那对我来说只是个玩笑还是我错过了什么?我尝试上传 zip 并将我的包上传到 S3 以检查它是否更快,但我仍然有相同的延迟。
我注意到 Python 版本可以本机执行 SQL 请求而无需任何自定义包装...
我们所有的应用程序都是用 node 编写的,所以我真的不想离开它,但是我很难理解为什么亚马逊不提供用于数据库交互的基本 npm 模块。
欢迎任何意见或帮助。在这一点上,我不确定如果 Lambda 需要 30 秒才能 运行 每分钟触发一个脚本...
有人遇到同样的问题吗?
更新:这就是您需要在不再需要时立即关闭连接的方式(再次感谢 Vitaly 的帮助):
exports.handler = function(event, context, callback) {
[...]
db.many(query, { status: 2, now: now.toISOString() }).then(function(data) {
pgp.end(); // <-- This is important to close the connection directly after the request
[...]
执行时间应根据正在执行的操作的长度来衡量,而不是应用程序退出所需的时间。
有许多库以一种或另一种形式使用连接池。这些通常会在一段可配置的不活动时间后终止。
如果是pg-promise, which in turn uses node-postgres, such period of inactivity is determined by parameter poolIdleTimeout, which defaults to 30 seconds. With pg-promise,您可以通过pgp.pg.defaults.poolIdleTimeout
访问它。
如果您希望您的进程在执行完最后一个查询后退出,您需要通过调用 pgp.end()
来关闭连接池。有关详细信息,请参阅第 Library de-initialization 章。
在大多数code examples中也有显示,因为那些需要在完成后立即退出。