feat(prodsqlconnection): added in prod connection with restart attempts and fail with notify

This commit is contained in:
2025-09-01 16:46:29 -05:00
parent bfb62df445
commit 083f38a079
11 changed files with 315 additions and 44 deletions

View File

@@ -0,0 +1,58 @@
import { env } from "../utils/envValidator.js";
import { returnFunc } from "../utils/return.js";
import { connected, pool } from "./prodSqlConnect.js";
/**
* Run a prod query
* just pass over the query as a string and the name of the query.
* Query should be like below.
* * select * from AlplaPROD_test1.dbo.table
* You must use test1 always as it will be changed via query
*/
export async function prodQuery(queryToRun: string, name: string) {
if (!connected) {
return returnFunc({
success: false,
module: "prodSql",
subModule: "query",
level: "error",
message: `The sql ${env.PROD_PLANT_TOKEN} is not connected`,
notify: false,
data: [],
});
}
const query = queryToRun.replaceAll("test1", env.PROD_PLANT_TOKEN);
try {
const result = await pool.request().query(query);
return {
success: true,
message: `Query results for: ${name}`,
data: result.recordset,
};
} catch (error: any) {
if (error.code === "ETIMEOUT") {
return returnFunc({
success: false,
module: "prodSql",
subModule: "query",
level: "error",
message: `${name} did not run due to a timeout.`,
notify: false,
data: [error],
});
}
if (error.code === "EREQUEST") {
return returnFunc({
success: false,
module: "prodSql",
subModule: "query",
level: "error",
message: `${name} encoutnered an error ${error.originalError.info.message}`,
data: [],
});
}
}
}

View File

@@ -3,9 +3,11 @@ import { checkHostnamePort } from "../utils/checkHostNamePort.js";
import { sqlConfig } from "./prodSqlConfig.js";
import { env } from "../utils/envValidator.js";
import { createLogger } from "../logger/logger.js";
import { returnFunc } from "../utils/return.js";
let pool;
let connected: boolean = false;
export let pool: any;
export let connected: boolean = false;
let reconnecting = false;
export const initializeProdPool = async () => {
const log = createLogger({ module: "prodSql" });
@@ -13,36 +15,120 @@ export const initializeProdPool = async () => {
const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);
if (!serverUp) {
log.error(`The sql ${process.env.PROD_SERVER} is not reachable`);
return {
reconnectToSql();
return returnFunc({
success: false,
module: "prodSql",
level: "fatal",
message: `The sql ${env.PROD_SERVER} is not reachable`,
data: [],
};
});
}
// if you were restarting from the endpoint you get this lovely error
if (connected) {
log.error("There is already a connection.");
return { success: false, message: "There is already a connection." };
return returnFunc({
success: false,
module: "prodSql",
level: "error",
message: `There is already a connection to ${env.PROD_PLANT_TOKEN}`,
data: [],
});
}
try {
pool = sql.connect(sqlConfig);
log.info(
`Connected to ${sqlConfig?.server}, and looking at ${sqlConfig?.database}`
`Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}`
);
connected = true;
return {
success: true,
message: "The sql server connection has been closed",
};
} catch (error) {
log.fatal(
`${JSON.stringify(
error
)}, "There was an error connecting to the pool."`
);
reconnectToSql();
// throw new Error("There was an error closing the sql connection");
}
};
const reconnectToSql = async () => {
const log = createLogger({ module: "prodSql" });
if (reconnecting) return;
reconnecting = true;
let delay = 2000; // start at 2s
let attempts = 0;
const maxAttempts = 10; // or limit by time, e.g. 2 min total
while (!connected && attempts < maxAttempts) {
attempts++;
log.info(
`Reconnect attempt ${attempts}/${maxAttempts} in ${
delay / 1000
}s...`
);
await new Promise((res) => setTimeout(res, delay));
const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`);
if (!serverUp) {
delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
continue;
}
try {
pool = sql.connect(sqlConfig);
log.info(
`Connected to ${sqlConfig?.server}, and looking at ${sqlConfig?.database}`
);
reconnecting = false;
connected = true;
} catch (error) {
log.fatal(
`${JSON.stringify(
error
)}, "There was an error connecting to the pool."`
);
delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
// throw new Error("There was an error closing the sql connection");
}
}
if (!connected) {
log.fatal(
{ notify: true },
"Max reconnect attempts reached on the prodSql server. Stopping retries."
);
reconnecting = false;
// optional: exit process or alert someone here
// process.exit(1);
}
};
export const closePool = async () => {
const log = createLogger({ module: "prodSql" });
if (!connected) {
log.error("There is no connection a connection.");
return { success: false, message: "There is already a connection." };
}
try {
await pool.close();
log.info("Connection pool closed");
connected = false;
return {
success: true,
message: "The sql server connection has been closed",
};
} catch (error) {
log.fatal(
{ notify: true },
`${JSON.stringify(
error
)}, "There was an error closing the sql connection"`
);
}
};