【问题标题】:Lambda function completes, but query to RDS is incompleteLambda 函数完成,但对 RDS 的查询不完整
【发布时间】: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  

请您建议并告诉我执行它的最佳方法是什么??

【问题讨论】:

  • 请帮助任何人?

标签: node.js amazon-web-services aws-lambda amazon-rds


【解决方案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进程将会终止
猜你喜欢
  • 1970-01-01
  • 2018-09-04
  • 1970-01-01
  • 2021-03-23
  • 2019-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多