multibridge
Version:
A multi-database connection framework with centralized configuration
202 lines (201 loc) • 9.44 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getConnection = getConnection;
exports.closeConnection = closeConnection;
exports.closeAllConnections = closeAllConnections;
const dbConfig_1 = require("../config/dbConfig");
const tenantContext_1 = require("../context/tenantContext");
const postgres_1 = require("./postgres");
const mysql_1 = require("./mysql");
const mongodb_1 = require("./mongodb");
const cassandra_1 = require("./cassandra");
const loggers_1 = __importDefault(require("../utils/loggers"));
const connectionCache = new Map();
function generateCacheKey(appid, orgid, appdbname) {
return `${appid}-${orgid}-${appdbname}`;
}
function isSQLConnectionValid(connection) {
return __awaiter(this, void 0, void 0, function* () {
try {
yield connection.query("SELECT 1");
return true;
}
catch (error) {
return false;
}
});
}
/**
* Retrieves a tenant-specific connection.
* Checks the cache for an existing connection and validates it.
* If the cached connection is stale or missing, creates a new connection.
*/
function getConnection(tenant) {
return __awaiter(this, void 0, void 0, function* () {
const currentTenant = tenant || (0, tenantContext_1.getTenant)();
if (!currentTenant) {
throw new Error("No tenant context available");
}
const { appid, orgid, appdbname } = currentTenant;
const cacheKey = generateCacheKey(appid, orgid, appdbname);
// Check if a connection is cached
if (connectionCache.has(cacheKey)) {
const cached = connectionCache.get(cacheKey);
if (cached.dbType === "postgres" || cached.dbType === "mysql") {
// Check if the SQL connection is still healthy
const valid = yield isSQLConnectionValid(cached.connection);
if (valid) {
loggers_1.default.info(`[MultiBridge] Reusing valid connection for ${cacheKey}`);
return cached;
}
else {
loggers_1.default.warn(`[MultiBridge] Cached SQL connection for ${cacheKey} is stale. Recreating connection.`);
connectionCache.delete(cacheKey);
}
}
else {
// For MongoDB and Cassandra, we assume the connection is valid (you can add health checks as needed)
loggers_1.default.info(`[MultiBridge] Reusing connection for ${cacheKey}`);
return cached;
}
}
// No valid cached connection; fetch configuration from central DB
const dbConfig = yield (0, dbConfig_1.fetchDBConfig)(appid, orgid);
if (!dbConfig) {
throw new Error(`No configuration found for appid: ${appid}, orgid: ${orgid}`);
}
// Use tenant.appdbname if provided; otherwise, use the default schema from config
const schema = appdbname || dbConfig.schema;
let connection;
const dbType = dbConfig.db_type;
try {
switch (dbType) {
case "postgres":
connection = yield (0, postgres_1.createPostgresConnection)({
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
schema,
});
break;
case "mysql":
connection = yield (0, mysql_1.createMySQLConnection)({
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
schema,
});
break;
case "mongodb":
connection = yield (0, mongodb_1.createMongoDBConnection)({
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
});
break;
case "cassandra":
connection = yield (0, cassandra_1.createCassandraConnection)({
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
dataCenter: dbConfig.data_center,
});
break;
default:
throw new Error(`Unsupported database type: ${dbConfig.db_type}`);
}
}
catch (error) {
loggers_1.default.error(`Error creating connection for ${cacheKey}: ${error.message}`);
throw error;
}
const ret = { connection, dbType, config: { schema } };
connectionCache.set(cacheKey, ret);
loggers_1.default.info(`[MultiBridge] Created new connection for ${cacheKey}`);
return ret;
});
}
function closeConnection(tenant) {
return __awaiter(this, void 0, void 0, function* () {
const currentTenant = tenant || (0, tenantContext_1.getTenant)();
if (!currentTenant)
return;
const cacheKey = generateCacheKey(currentTenant.appid, currentTenant.orgid, currentTenant.appdbname);
if (connectionCache.has(cacheKey)) {
const { connection, dbType } = connectionCache.get(cacheKey);
if (connection) {
try {
if ((dbType === "postgres" || dbType === "mysql") && connection.end) {
yield connection.end();
loggers_1.default.info(`[MultiBridge] SQL connection closed for ${cacheKey}`);
}
else if (dbType === "mongodb" && connection.close) {
yield connection.close();
loggers_1.default.info(`[MultiBridge] MongoDB connection closed for ${cacheKey}`);
}
else if (dbType === "cassandra" && connection.shutdown) {
yield connection.shutdown();
loggers_1.default.info(`[MultiBridge] Cassandra connection closed for ${cacheKey}`);
}
else {
loggers_1.default.warn(`[MultiBridge] Unknown DB type or close method missing for ${cacheKey}`);
}
}
catch (error) {
loggers_1.default.error(`Error closing connection for ${cacheKey}: ${error.message}`);
}
}
connectionCache.delete(cacheKey);
}
});
}
function closeAllConnections() {
return __awaiter(this, void 0, void 0, function* () {
for (const [cacheKey, { connection, dbType }] of connectionCache.entries()) {
if (connection) {
try {
if ((dbType === "postgres" || dbType === "mysql") && connection.end) {
yield connection.end();
loggers_1.default.info(`[MultiBridge] SQL connection closed for ${cacheKey}`);
}
else if (dbType === "mongodb" && connection.close) {
yield connection.close();
loggers_1.default.info(`[MultiBridge] MongoDB connection closed for ${cacheKey}`);
}
else if (dbType === "cassandra" && connection.shutdown) {
yield connection.shutdown();
loggers_1.default.info(`[MultiBridge] Cassandra connection closed for ${cacheKey}`);
}
else {
loggers_1.default.warn(`[MultiBridge] Unknown DB type or close method missing for ${cacheKey}`);
}
}
catch (error) {
loggers_1.default.error(`Error closing connection for ${cacheKey}: ${error.message}`);
}
}
}
connectionCache.clear();
loggers_1.default.info("[MultiBridge] All connections closed.");
});
}