我正在开发一个应用程序,该应用程序使用Firebase函数作为web应用程序和Google Cloud SQL(MySQL 5.7(之间的API接口
我有一个从客户端应用程序导入记录的过程;基本上,客户端应用程序读取CSV文件,然后为CSV文件中的每一行执行一个函数。该函数在处理记录期间执行三到四个查询(检查主记录是否存在,创建它和/或其他需要的记录,更新此过程的统计记录(。
函数是按顺序为每一行调用的,因此在将数据返回给客户端应用程序之前,一次处理的请求(行(永远不会超过一个,执行3或4个查询,然后客户端应用程序处理下一行(async/await(。
该过程适用于具有1到100行的CSV文件。一旦超过大约900行,Firebase函数就会开始报告ERROR Error: ER_CON_COUNT_ERROR: Too many connections
我的代码,如下所示,最初的连接限制为10,但我将其增加到了100个连接,但它仍然失败。
以下是我执行SQL查询的代码:
import * as functions from "firebase-functions";
import * as mysql from 'mysql';
export async function executeQuery(cmd: string) {
const mySQLConfig = {
host: functions.config().sql.prodhost,
user: functions.config().sql.produser,
password: functions.config().sql.prodpswd,
database: functions.config().sql.proddatabase,
connectionLimit: 100,
}
var pool: any;
if (!pool) {
pool = mysql.createPool(mySQLConfig);
}
return new Promise(function (resolve, reject) {
//@ts-ignore
pool.query(cmd, function (error, results) {
if (error) {
return reject(error);
}
resolve(results);
});
});
}
据我所知,使用我认为已经在上面实现的池,每个请求都将获得一个最大连接数的连接。处理完请求后,每个连接都将自动返回到池中。因此,即使释放连接需要一段时间,在连接限制为100的情况下,在出现连接争用之前,我也应该能够处理相当多的行(至少20行左右(,然后进程将排队等待空闲连接,然后再继续。如果是这样的话,这里发生了什么?
我在这里找到了一篇文章:https://cloud.google.com/sql/docs/mysql/manage-connections描述了一些我可以用来调整连接管理的附加设置:
// 'connectTimeout' is the maximum number of milliseconds before a timeout
// occurs during the initial connection to the database.
connectTimeout: 10000,
// 'acquireTimeout' is the maximum number of milliseconds to wait when
// checking out a connection from the pool before a timeout error occurs.
acquireTimeout: 10000,
// 'waitForConnections' determines the pool's action when no connections are
// free. If true, the request will queued and a connection will be presented
// when ready. If false, the pool will call back with an error.
waitForConnections: true, // Default: true
// 'queueLimit' is the maximum number of requests for connections the pool
// will queue at once before returning an error. If 0, there is no limit.
queueLimit: 0, // Default: 0
我很想尝试增加暂停时间,但我不确定这是否真的影响了我。既然我在Firebase函数(封面下的谷歌云函数(中运行这个,这些设置真的适用吗?我的函数的VM不是在每次执行后都会重置吗?或者至少我的函数在每次执行之后都会终止吗?在这种情况下,池是否存在?如果没有,那么如何在函数中进行这种类型的处理?
当然,一种选择是将我的所有处理推送给函数,只需为行数组发送一个JSON对象,然后让函数一次处理所有处理。我认为,这应该适当利用池,但我担心我会在函数(5分钟(中遇到执行限制,这就是为什么我像以前那样构建它。
愚蠢的开发人员技巧,我非常关注我的池代码,以至于我错过了在错误的地方声明池变量。将池声明移到方法之外解决了我的问题。按照代码的方式,我为每个SQL查询创建了一个池,它很快就用完了我的所有连接。