Lambda 函数完成,但对 RDS 的查询不完整
Posted
技术标签:
【中文标题】Lambda 函数完成,但对 RDS 的查询不完整【英文标题】:Lambda function completes, but query to RDS is incomplete 【发布时间】:2020-04-11 14:52:30 【问题描述】:我试图使用 handler.async 对数据库 (RDS) 进行后查询。 但是,我遇到了以下问题。
有一半时间,lambda 函数完成,但查询未成功发送到 RDS。另一半时间,它将完全发送到 lambda。尝试添加一个 setTimeout 函数以将 lambda 执行时间增加 3 秒,并且查询将一直发送。
日志也会显示错误:
INFO 错误:致命错误后无法将查询排入队列。
以下是我的代码:
var mysql = require('mysql');
var connection = mysql.createConnection(
host : '***',
user : '***',
password : '***',
database : '***'
);
exports.handler = async (event) =>
const sql = `INSERT INTO forms VALUES(777,2,3,4,5,6,7,8,9,10,11);`;
const query = (x) =>
return new Promise ((resolve,reject)=>
resolve(connection.query(x, function (error, results, fields)
console.log(error)
console.log(results)
console.log(fields)
)))
await query(sql)
具有超时功能,
var mysql = require('mysql');
var connection = mysql.createConnection(
host : '***',
user : '***',
password : '***',
database : '***'
);
exports.handler = async (event) =>
const sql = `INSERT INTO forms VALUES(777,2,3,4,5,6,7,8,9,10,11);`;
const query = (x) =>
return new Promise ((resolve,reject)=>
resolve(connection.query(x, function (error, results, fields)
console.log(error)
console.log(results)
console.log(fields)
)))
await query(sql)
await wait(3000)
const wait = (x) =>
return new Promise ((resolve,reject)=>
setTimeout(()=>resolve(console.log("delay")), x);
)
第一个值是主键。发送一个常量 777 进行检查,如果错误显示主键重复,则表示查询发送成功。如果没有错误,则表示尽管 lambda 完成,但查询未成功发送。
execution result succeeded but shows:
START RequestId: e541fe4b-6927-4fbb-90b4-750f77e5f460 Version: $LATEST
2019-12-19T01:54:45.212Z e541fe4b-6927-4fbb-90b4-750f77e5f460 INFO Error: **Cannot enqueue Query after fatal error**.
at Protocol._validateEnqueue (/var/task/node_modules/mysql/lib/protocol/Protocol.js:212:16)
at Protocol._enqueue (/var/task/node_modules/mysql/lib/protocol/Protocol.js:138:13)
at Connection.query (/var/task/node_modules/mysql/lib/Connection.js:201:25)
at /var/task/index.js:14:24
at new Promise (<anonymous>)
at query (/var/task/index.js:13:10)
at Runtime.exports.handler (/var/task/index.js:20:7)
at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)
code: 'PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR',
fatal: false
2019-12-19T01:54:45.213Z e541fe4b-6927-4fbb-90b4-750f77e5f460 INFO undefined2019-12-19T01:54:45.213Z e541fe4b-6927-4fbb-90b4-750f77e5f460 INFO undefined2019-12-19T01:54:45.262Z e541fe4b-6927-4fbb-90b4-750f77e5f460 INFO delayEND RequestId: e541fe4b-6927-4fbb-90b4-750f77e5f460
REPORT RequestId: e541fe4b-6927-4fbb-90b4-750f77e5f460 Duration: 51.09 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 80 MB
请您建议并告诉我执行它的最佳方法是什么??
【问题讨论】:
请帮助任何人? 【参考方案1】:在任何环境中管理 RDBMS 连接都不是一件容易的事。 Lambda 在这里增加了一层复杂性。您需要了解热重启和冷重启之间的区别,这对于在处理程序函数之外创建的资源意味着什么,何时适合使用连接池,以及何时以及如何释放连接。
与数据库的持久连接并不特别适合微服务、FaaS 环境(如 Lambda)。这就是 Aurora Serverless 支持 HTTP Data API 的原因之一(希望其他数据库引擎在某个时候也能支持)。
阅读How To: Manage RDS Connections from AWS Lambda Serverless Functions。
还要注意新的Amazon RDS Proxy with AWS Lambda。
在您的特定情况下,最明显的问题是您重复创建数据库连接但从未释放它们(除非这是我不知道的 mysql 包的 query
函数的内置功能)。
【讨论】:
@excitelybored 如果提供的回复之一有助于回答您的问题,请选择它作为答案。如果没有,请考虑写一个答案并选择它。【参考方案2】:您可以将 lambda 超时时间延长至 15 分钟。但是如果你通过 api 网关调用 lambda,超时是 29 秒。
这是为我工作的代码。
const mysql = require('mysql');
const con = mysql.createConnection(
host: process.env.RDS_HOSTNAME,
user: process.env.RDS_USERNAME,
password: process.env.RDS_PASSWORD,
port: process.env.RDS_PORT,
connectionLimit: 10,
multipleStatements: true,// Prevent nested sql statements
debug: true
// ,database:'testdb1'
);
exports.handler = async (event) =>
try
const data = await new Promise((resolve, reject) =>
con.connect(function (err)
if (err)
reject(err);
const sql = `INSERT INTO forms VALUES(777,2,3,4,5,6,7,8,9,10,11);`;
con.query(sql, function (err, result)
if (err)
console.log("Error->" + err);
reject(err);
resolve(result);
);
)
);
return
statusCode: 200,
body: JSON.stringify(data)
catch (err)
return
statusCode: 400,
body: err.message
;
参考:aws lambda with rds mysql DDL command not working
【讨论】:
我在您的代码中看到的主要问题是,您没有正确解析承诺,它应该是connection.query(x, function (error, results, fields) resolve() )
,而是将查询函数作为参数传递给解析函数。我不明白为什么。
我认为那是因为您没有释放连接。查询完成后尝试做connection.release()。或者您可以在配置中配置一个池
嗨阿伦克。我设法让它工作。非常感谢。只是一个简单的新手问题,是用于调试的try..catch。我可以删除它们还是更好地放置它们。
尝试捕捉很重要。首先,它将帮助您从 api 返回有关异常的友好消息。如果没有 try catch ,应用程序将从 api 发送确切的丑陋错误。
其次,对于promise的拒绝必须要try catch,在以后的node版本中,如果promise拒绝没有在app内部处理,nodejs进程将会终止以上是关于Lambda 函数完成,但对 RDS 的查询不完整的主要内容,如果未能解决你的问题,请参考以下文章
使用 rds-data 增加来自 execute_sql 的 aws lambda 结果计数的 1000 限制或使用不同的包?