节点 js 共享变量和多个用户和多个入口点
Node js shared variables and multiple users and multiple entry-points
我有一个 node-js 应用程序,我正在从单租户数据库切换到多租户数据库。应用程序代码是从快递 api 调用的,但也有服务 运行 通过不同的入口点,因此 req.session 并不总是可用。
目前我在整个应用程序中都有数据库函数调用,例如:
database.select.users.findByUserId(123, callback)
由于应用正在更改为多租户数据库,我需要能够将 postgreSQL schemaName 发送到数据库函数。我知道我可以编辑每个数据库调用的签名:
database.select.users.findByUserId(schemaName, 123, callback)
但它非常耗费人力,范围广泛,并且会产生很多错误。我希望找到一种安全的方法将 postgres schemaName 传递给数据库包装器,而不会出现某种竞争条件,即这个“全局”schemaName 变量以某种方式被另一个调用者覆盖,从而发送错误的数据。
这是我正在考虑编写的一些伪代码,但我担心一旦我们部署它就不会是“线程安全的”。
// as early as possible in the app call:
database.session.initSchema('schema123');
//session.js
let schema = null;
module.exports.initSchema = function (s) {
schema = s;
};
module.exports.getSchema = function () {
return schema;
};
// before I hit the database, i would call getSchema() and pass it to postgreSQL
这种方法可行,但是如果 Caller2 调用 initForSchema() 时调用了不同的值,而 Caller1 还没有执行完怎么办?使用这样的一个变量时,如何区分哪个调用者正在请求数据?有没有什么办法可以让我安全地解决这个问题而无需编辑每个数据库函数调用的签名?谢谢指教。
编辑
我倾向于这个解决方案:
database.session.initSchema('schema123');
//then immediately call
database.select.users.findByUserId(123, callback);
这里的优点是两个调用之间不会发生异步,这应该可以消除竞争条件的可能性,同时保持原始的 findByUserId 签名。
我认为按照您的想法行事是行不通的,因为我看不出有什么方法可以解决这些竞争条件。如果你这样做:
app.use((request, response, next) => {
// initialize database schema
next()
})
这将是理想的,因为这样您就可以在所有路由中只执行一次,但另一个请求可能会在一毫秒后到达服务器并再次更改架构。
或者,您可以在每个单独的路由中执行此操作,这会起作用,但是您所做的工作与首先在数据库调用中执行的工作一样多。如果您必须在每个路由中重新初始化架构,那么这与在调用本身中执行它是一样的。
我考虑了一段时间的解决方案,然后我能想到的最好的办法是你是否可以在连接池本身中完成它。我不知道您使用的是什么包,也不知道它是如何创建数据库连接的。但是像这样:
const database = connection.getInstance('schemaExample')
// continue to do database things here
只是为了展示我的想法的一个例子。这样你就可以在启动时为不同的模式创建多个连接池,你可以只查询具有正确模式的连接池,避免所有竞争条件。
想法是即使现在有另一个请求使用不同的模式,它也会在不同的数据库连接上执行。
我有一个 node-js 应用程序,我正在从单租户数据库切换到多租户数据库。应用程序代码是从快递 api 调用的,但也有服务 运行 通过不同的入口点,因此 req.session 并不总是可用。
目前我在整个应用程序中都有数据库函数调用,例如:
database.select.users.findByUserId(123, callback)
由于应用正在更改为多租户数据库,我需要能够将 postgreSQL schemaName 发送到数据库函数。我知道我可以编辑每个数据库调用的签名:
database.select.users.findByUserId(schemaName, 123, callback)
但它非常耗费人力,范围广泛,并且会产生很多错误。我希望找到一种安全的方法将 postgres schemaName 传递给数据库包装器,而不会出现某种竞争条件,即这个“全局”schemaName 变量以某种方式被另一个调用者覆盖,从而发送错误的数据。
这是我正在考虑编写的一些伪代码,但我担心一旦我们部署它就不会是“线程安全的”。
// as early as possible in the app call:
database.session.initSchema('schema123');
//session.js
let schema = null;
module.exports.initSchema = function (s) {
schema = s;
};
module.exports.getSchema = function () {
return schema;
};
// before I hit the database, i would call getSchema() and pass it to postgreSQL
这种方法可行,但是如果 Caller2 调用 initForSchema() 时调用了不同的值,而 Caller1 还没有执行完怎么办?使用这样的一个变量时,如何区分哪个调用者正在请求数据?有没有什么办法可以让我安全地解决这个问题而无需编辑每个数据库函数调用的签名?谢谢指教。
编辑
我倾向于这个解决方案:
database.session.initSchema('schema123');
//then immediately call
database.select.users.findByUserId(123, callback);
这里的优点是两个调用之间不会发生异步,这应该可以消除竞争条件的可能性,同时保持原始的 findByUserId 签名。
我认为按照您的想法行事是行不通的,因为我看不出有什么方法可以解决这些竞争条件。如果你这样做:
app.use((request, response, next) => {
// initialize database schema
next()
})
这将是理想的,因为这样您就可以在所有路由中只执行一次,但另一个请求可能会在一毫秒后到达服务器并再次更改架构。
或者,您可以在每个单独的路由中执行此操作,这会起作用,但是您所做的工作与首先在数据库调用中执行的工作一样多。如果您必须在每个路由中重新初始化架构,那么这与在调用本身中执行它是一样的。
我考虑了一段时间的解决方案,然后我能想到的最好的办法是你是否可以在连接池本身中完成它。我不知道您使用的是什么包,也不知道它是如何创建数据库连接的。但是像这样:
const database = connection.getInstance('schemaExample')
// continue to do database things here
只是为了展示我的想法的一个例子。这样你就可以在启动时为不同的模式创建多个连接池,你可以只查询具有正确模式的连接池,避免所有竞争条件。
想法是即使现在有另一个请求使用不同的模式,它也会在不同的数据库连接上执行。