问题描述
首次使用“免费套餐”设置Heroku的postgres服务。我使用heroku来托管带有pg数据库的koa服务器。服务器通过knexjs与数据库进行通信。我不确定我是否使用了不正确的knexjs,因为每次我运行查询时,它都会创建一个新连接,如通过Heroku的仪表板看到的那样,最终会耗尽连接。另外,我注意到它们是主要消耗我连接的内部IP(即10.1 ...)。如果我杀死了它们,那么我的连接将降为0。我的knex查询如下:
出于缓存目的,我在每个连接上启动了一个类(仅在同一客户端请求期间运行多个查询时才有用)。
import knexDefault from "knex";
import { development,production } from "../ConfigKnex";
import { ENVTRANS } from "./Consts";
const { ISDEV } = ENVTRANS;
export class KnexCache(){
knex = knexDefault(ISDEV ? development : production);
transaction = this.knex.transaction.bind(this.knex);
constructor(private cache: Map<string,any> = new Map()) {}
private CacheIt(action: ActionTypes,table: string,props: any,fn: any) {
let tm = this.cache.get(table);
if (!tm) {
tm = new Map<string,any>();
this.cache.set(table,tm);
}
const key = `${action}|${JSON.stringify(props)}`;
let res = tm.get(key);
if (res) return res;
res = fn();
tm.set(key,res);
return res;
}
async SelectAsync<T>(
table: string,where: Partial<T>,db = this.knex,): Promise<T[]> {
return this.CacheIt("SelectAsync",table,{ where },() =>
db(table).where(where).select(),);
}
...
}
我使用GraphQL(因此称为ApolloServer)在每个连接上创建一个新的KnexCache。
const server = new ApolloServer({
typeDefs,resolvers,// schemaDirectives,debug: ISDEV,tracing: ISDEV,playground: {
settings: {
"request.credentials": "include",},context: async (context) => {
context.k = new KnexCache();
return context as Context;
},});
然后在我的解析器中调用
export const resolvers = {
Query: {
GetData: async (p,a,c,i) => {
const { k } = c;
return k.SelectAsync<TABLETYPE>("TABLENAME",{ id: "someId" });
},};
一切正常,但是我是否以不正确的方式使用knex来保持连接活动和/或防止连接重用?如何“修复”代码以正确重用knex的连接池中的连接?
解决方法
我知道了。由于我为每个连接创建一个新类,因此将为每个访问者建立一个新的knex连接。我尝试将knex属性设为静态,但显然在javascript中,静态属性只能由静态方法访问...因此,我将knex属性移至类之外,并将其转换为export const
。