Revision 79e60926-3559-40e6-8b6a-e09001a5995e - Code Review Stack Exchange
I was facing an issue with changing models on the fly — since we don’t just need isolation based on string or ID, but also data-level differences for each HIMS instance. To handle this, I created a simple library. Could you help me verify if this approach will work, and point out any potential issues I might face with aggregation? I’m already aware that aggregation can't be performed between two different databases.
// utils/TenantConnectionManager.js
import mongoose from "mongoose";
class TenantConnectionManager {
constructor() {
this.connections = {}; // { apiKey: { conn, timer } }
this.TIMEOUT = 60 * 60 * 1000; // 1 hour
}
/**
* Get or create a tenant connection
*/
async getConnection(apiKey, dbURI) {
if (this.connections[apiKey]) {
// Reset timeout
clearTimeout(this.connections[apiKey].timer);
this.connections[apiKey].timer = setTimeout(() => {
this.disconnect(apiKey);
}, this.TIMEOUT);
return this.connections[apiKey].conn;
}
// Create fresh connection
const conn = await mongoose.createConnection(dbURI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const timer = setTimeout(() => {
this.disconnect(apiKey);
}, this.TIMEOUT);
this.connections[apiKey] = { conn, timer };
console.log(`✅ Connected to tenant DB for API key: ${apiKey}`);
return conn;
}
/**
* Disconnect tenant DB
*/
async disconnect(apiKey) {
if (this.connections[apiKey]) {
await this.connections[apiKey].conn.close();
clearTimeout(this.connections[apiKey].timer);
delete this.connections[apiKey];
console.log(`❌ Disconnected tenant DB for API key: ${apiKey}`);
}
}
/**
* Register a model on a tenant connection
*/
async setModel(apiKey, dbURI, modelName, schema) {
const conn = await this.getConnection(apiKey, dbURI);
if (!conn.models[modelName]) {
try {
conn.model(modelName, schema);
} catch (err) {
if (err.name !== "OverwriteModelError") throw err;
}
}
return conn.model(modelName);
}
/**
* Get a registered model
*/
async getModel(apiKey, dbURI, modelName) {
const conn = await this.getConnection(apiKey, dbURI);
if (!conn.models[modelName]) {
throw new Error(
`Model "${modelName}" not registered for tenant ${apiKey}`
);
}
return conn.model(modelName);
}
}
export default new TenantConnectionManager();