feat(db): prod sql connect setup more proper to handle errors as well
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import express from "express";
|
||||
import { connectProdSql } from "./src/prodSql/sqlConnection.controller.js";
|
||||
import { setupRoutes } from "./src/routeHandler.route.js";
|
||||
|
||||
const port = Number(process.env.PORT);
|
||||
@@ -6,6 +7,9 @@ export const baseUrl = "";
|
||||
const startApp = async () => {
|
||||
const app = express();
|
||||
|
||||
// start the connection to the prod sql server
|
||||
connectProdSql();
|
||||
|
||||
setupRoutes(baseUrl, app);
|
||||
|
||||
app.listen(port, () => {
|
||||
|
||||
19
backend/src/configs/prodSql.config.ts
Normal file
19
backend/src/configs/prodSql.config.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type sql from "mssql";
|
||||
export const prodSqlConfig: sql.config = {
|
||||
server: `${process.env.PROD_SERVER}`,
|
||||
database: `AlplaPROD_${process.env.PROD_PLANT_TOKEN}_cus`,
|
||||
user: process.env.PROD_USER,
|
||||
password: process.env.PROD_PASSWORD,
|
||||
options: {
|
||||
encrypt: true,
|
||||
trustServerCertificate: true,
|
||||
},
|
||||
requestTimeout: 90000, // how long until we kill the query and fail it
|
||||
pool: {
|
||||
max: 20, // Maximum number of connections in the pool
|
||||
min: 0, // Minimum number of connections in the pool
|
||||
idleTimeoutMillis: 10000, // How long a connection is allowed to be idle before being released
|
||||
reapIntervalMillis: 1000, // how often to check for idle resources to destroy
|
||||
acquireTimeoutMillis: 100000, // How long until a complete timeout happens
|
||||
},
|
||||
};
|
||||
5
backend/src/prodSql/sql.route.ts
Normal file
5
backend/src/prodSql/sql.route.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { Router } from "express";
|
||||
|
||||
const r = Router();
|
||||
|
||||
export default r;
|
||||
135
backend/src/prodSql/sqlConnection.controller.ts
Normal file
135
backend/src/prodSql/sqlConnection.controller.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import sql from "mssql";
|
||||
import { prodSqlConfig } from "../configs/prodSql.config.js";
|
||||
import { checkHostnamePort } from "../utils/checkHost.utils.js";
|
||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||
|
||||
export let pool: sql.ConnectionPool;
|
||||
export let connected: boolean = false;
|
||||
export let reconnecting = false;
|
||||
|
||||
export const connectProdSql = async () => {
|
||||
const serverUp = await checkHostnamePort(`${process.env.PROD_SERVER}:1433`);
|
||||
|
||||
if (!serverUp) {
|
||||
// we will try to reconnect
|
||||
connected = false;
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "db",
|
||||
message: "Prod server is offline or unreachable.",
|
||||
});
|
||||
}
|
||||
|
||||
// if we are trying to click restart from the api for some reason we want to kick back and say no
|
||||
if (connected) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "db",
|
||||
message: "The Sql server is already connected.",
|
||||
});
|
||||
}
|
||||
|
||||
// try to connect to the sql server
|
||||
try {
|
||||
pool = await sql.connect(prodSqlConfig);
|
||||
connected = true;
|
||||
console.log(
|
||||
`${prodSqlConfig.server} is connected to ${prodSqlConfig.database}`,
|
||||
);
|
||||
} catch (error) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "db",
|
||||
message: "Failed to connect to the prod sql server.",
|
||||
data: [error],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const closePool = async () => {
|
||||
if (!connected) {
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "db",
|
||||
message: "There is no connection to the prod server currently.",
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await pool.close();
|
||||
console.log("Connection pool closed");
|
||||
connected = false;
|
||||
return {
|
||||
success: true,
|
||||
message: "The sql server connection has been closed",
|
||||
};
|
||||
} catch (error) {
|
||||
connected = false;
|
||||
console.log("There was an error closing the sql connection", error);
|
||||
}
|
||||
};
|
||||
export const reconnectToSql = async () => {
|
||||
if (reconnecting) return;
|
||||
|
||||
//set reconnecting to true while we try to reconnect
|
||||
reconnecting = true;
|
||||
|
||||
// start the delay out as 2 seconds
|
||||
let delayStart = 2000;
|
||||
let attempt = 0;
|
||||
const maxAttempts = 10;
|
||||
|
||||
while (!connected && attempt < maxAttempts) {
|
||||
attempt++;
|
||||
console.log(
|
||||
`Reconnect attempt ${attempt}/${maxAttempts} in ${delayStart / 1000}s ...`,
|
||||
);
|
||||
|
||||
await new Promise((res) => setTimeout(res, delayStart));
|
||||
|
||||
const serverUp = await checkHostnamePort(`${process.env.PROD_SERVER}:1433`);
|
||||
|
||||
if (!serverUp) {
|
||||
delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
pool = await sql.connect(prodSqlConfig);
|
||||
reconnecting = false;
|
||||
connected = true;
|
||||
console.log(
|
||||
`${prodSqlConfig.server} is connected to ${prodSqlConfig.database}`,
|
||||
);
|
||||
} catch (error) {
|
||||
delayStart = Math.min(delayStart * 2, 30000);
|
||||
return returnFunc({
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "system",
|
||||
subModule: "db",
|
||||
message: "Failed to reconnect to the prod sql server.",
|
||||
data: [error],
|
||||
notify: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
console.log(
|
||||
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
||||
);
|
||||
|
||||
reconnecting = false;
|
||||
// exit alert someone here
|
||||
}
|
||||
};
|
||||
0
backend/src/prodSql/sqlQuery.controller.ts
Normal file
0
backend/src/prodSql/sqlQuery.controller.ts
Normal file
@@ -11,7 +11,7 @@
|
||||
"build": "esbuild backend/app.ts --bundle --platform=node --minify --outfile=dist/index.js --format=esm --packages=external",
|
||||
"build:app": "ncc build backend/app.ts -o dist -m -s",
|
||||
"lint": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"start": "dotenvx run -f .env -- node dist/index.js",
|
||||
"commit": "cz",
|
||||
"changeset": "changeset",
|
||||
"version": "changeset version",
|
||||
|
||||
Reference in New Issue
Block a user