Fixed repo count issue

Refactored code to remove duplicate backend api endpoints for counting
Improved connection persistence issues
Improved database connection pooling issues
Fixed redis connection efficiency
Changed version to 1.3.0
Fixed GO binary detection based on package manager rather than OS
This commit is contained in:
Muhammad Ibrahim
2025-10-19 17:53:10 +01:00
parent 30c89de134
commit c4d0d8bee8
42 changed files with 376 additions and 310 deletions

View File

@@ -0,0 +1,149 @@
/**
* Centralized Prisma Client Singleton
* Prevents multiple Prisma clients from creating connection leaks
*/
const { PrismaClient } = require("@prisma/client");
// Parse DATABASE_URL and add connection pooling parameters
function getOptimizedDatabaseUrl() {
const originalUrl = process.env.DATABASE_URL;
if (!originalUrl) {
throw new Error("DATABASE_URL environment variable is required");
}
// Parse the URL
const url = new URL(originalUrl);
// Add connection pooling parameters for multiple instances
url.searchParams.set("connection_limit", "5"); // Reduced from default 10
url.searchParams.set("pool_timeout", "10"); // 10 seconds
url.searchParams.set("connect_timeout", "10"); // 10 seconds
url.searchParams.set("idle_timeout", "300"); // 5 minutes
url.searchParams.set("max_lifetime", "1800"); // 30 minutes
return url.toString();
}
// Singleton Prisma client instance
let prismaInstance = null;
function getPrismaClient() {
if (!prismaInstance) {
const optimizedUrl = getOptimizedDatabaseUrl();
prismaInstance = new PrismaClient({
datasources: {
db: {
url: optimizedUrl,
},
},
log:
process.env.PRISMA_LOG_QUERIES === "true"
? ["query", "info", "warn", "error"]
: ["warn", "error"],
errorFormat: "pretty",
});
// Handle graceful shutdown
process.on("beforeExit", async () => {
await prismaInstance.$disconnect();
});
process.on("SIGINT", async () => {
await prismaInstance.$disconnect();
process.exit(0);
});
process.on("SIGTERM", async () => {
await prismaInstance.$disconnect();
process.exit(0);
});
}
return prismaInstance;
}
// Connection health check
async function checkDatabaseConnection(prisma) {
try {
await prisma.$queryRaw`SELECT 1`;
return true;
} catch (error) {
console.error("Database connection check failed:", error.message);
return false;
}
}
// Wait for database to be available with retry logic
async function waitForDatabase(prisma, options = {}) {
const maxAttempts =
options.maxAttempts ||
parseInt(process.env.PM_DB_CONN_MAX_ATTEMPTS, 10) ||
30;
const waitInterval =
options.waitInterval ||
parseInt(process.env.PM_DB_CONN_WAIT_INTERVAL, 10) ||
2;
if (process.env.ENABLE_LOGGING === "true") {
console.log(
`Waiting for database connection (max ${maxAttempts} attempts, ${waitInterval}s interval)...`,
);
}
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const isConnected = await checkDatabaseConnection(prisma);
if (isConnected) {
if (process.env.ENABLE_LOGGING === "true") {
console.log(
`Database connected successfully after ${attempt} attempt(s)`,
);
}
return true;
}
} catch {
// checkDatabaseConnection already logs the error
}
if (attempt < maxAttempts) {
if (process.env.ENABLE_LOGGING === "true") {
console.log(
`⏳ Database not ready (attempt ${attempt}/${maxAttempts}), retrying in ${waitInterval}s...`,
);
}
await new Promise((resolve) => setTimeout(resolve, waitInterval * 1000));
}
}
throw new Error(
`❌ Database failed to become available after ${maxAttempts} attempts`,
);
}
// Graceful disconnect with retry
async function disconnectPrisma(prisma, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
await prisma.$disconnect();
console.log("Database disconnected successfully");
return;
} catch (error) {
console.error(`Disconnect attempt ${i + 1} failed:`, error.message);
if (i === maxRetries - 1) {
console.error("Failed to disconnect from database after all retries");
} else {
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second
}
}
}
}
module.exports = {
getPrismaClient,
checkDatabaseConnection,
waitForDatabase,
disconnectPrisma,
};