diff --git a/app/src/pkg/prodSql/prodQuery.ts b/app/src/pkg/prodSql/prodQuery.ts index d31f4bc..2fac1b5 100644 --- a/app/src/pkg/prodSql/prodQuery.ts +++ b/app/src/pkg/prodSql/prodQuery.ts @@ -1,6 +1,12 @@ -import { returnFunc } from "../utils/return.js"; -import { connected, pool } from "./prodSqlConnect.js"; import { validateEnv } from "../utils/envValidator.js"; +import { returnFunc } from "../utils/return.js"; +import { + closePool, + connected, + pool, + reconnecting, + reconnectToSql, +} from "./prodSqlConnect.js"; const env = validateEnv(process.env); /** @@ -11,48 +17,65 @@ const env = validateEnv(process.env); * 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) { - console.log(error); - 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 (!connected) { + reconnectToSql(); - if (error.code === "EREQUEST") { - return returnFunc({ - success: false, - module: "prodSql", - subModule: "query", - level: "error", - message: `${name} encountered an error ${error.originalError.info.message}`, - data: [], - }); - } - } + if (reconnecting) { + return returnFunc({ + success: false, + module: "prodSql", + subModule: "query", + level: "error", + message: `The sql ${env.PROD_PLANT_TOKEN} is trying to reconnect already`, + notify: false, + data: [], + }); + } else { + 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) { + console.log(error); + if (error.code === "ETIMEOUT") { + closePool(); + 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") { + closePool(); + return returnFunc({ + success: false, + module: "prodSql", + subModule: "query", + level: "error", + message: `${name} encountered an error ${error.originalError.info.message}`, + data: [], + }); + } + } } diff --git a/app/src/pkg/prodSql/prodSqlConnect.ts b/app/src/pkg/prodSql/prodSqlConnect.ts index 7e92b30..cc84b64 100644 --- a/app/src/pkg/prodSql/prodSqlConnect.ts +++ b/app/src/pkg/prodSql/prodSqlConnect.ts @@ -1,136 +1,134 @@ import sql from "mssql"; -import { checkHostnamePort } from "../utils/checkHostNamePort.js"; -import { sqlConfig } from "./prodSqlConfig.js"; import { createLogger } from "../logger/logger.js"; -import { returnFunc } from "../utils/return.js"; +import { checkHostnamePort } from "../utils/checkHostNamePort.js"; import { validateEnv } from "../utils/envValidator.js"; +import { returnFunc } from "../utils/return.js"; +import { sqlConfig } from "./prodSqlConfig.js"; const env = validateEnv(process.env); export let pool: any; export let connected: boolean = false; -let reconnecting = false; +export let reconnecting = false; export const initializeProdPool = async () => { - const log = createLogger({ module: "prodSql" }); + const log = createLogger({ module: "prodSql" }); - const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`); + const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`); - if (!serverUp) { - reconnectToSql(); - return returnFunc({ - success: false, - module: "prodSql", - level: "fatal", - message: `The sql ${env.PROD_SERVER} is not reachable`, - data: [], - }); - } + if (!serverUp) { + 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) { - return returnFunc({ - success: false, - module: "prodSql", - level: "error", - message: `There is already a connection to ${env.PROD_PLANT_TOKEN}`, - data: [], - }); - } - try { - pool = await sql.connect(sqlConfig); + // if you were restarting from the endpoint you get this lovely error + if (connected) { + return returnFunc({ + success: false, + module: "prodSql", + level: "error", + message: `There is already a connection to ${env.PROD_PLANT_TOKEN}`, + data: [], + }); + } + try { + pool = await sql.connect(sqlConfig); - log.info( - `Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}` - ); - connected = true; - } 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"); - } + log.info( + `Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}`, + ); + connected = true; + } 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; +export 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 + 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...` - ); + while (!connected && attempts < maxAttempts) { + attempts++; + log.info( + `Reconnect attempt ${attempts}/${maxAttempts} in ${delay / 1000}s...`, + ); - await new Promise((res) => setTimeout(res, delay)); + await new Promise((res) => setTimeout(res, delay)); - const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`); + const serverUp = await checkHostnamePort(`${env.PROD_SERVER}:1433`); - if (!serverUp) { - delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s - continue; - } + if (!serverUp) { + delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s + continue; + } - try { - pool = sql.connect(sqlConfig); + 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"); - } - } + 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); - } + if (!connected) { + log.fatal( + { notify: true }, + "Max reconnect attempts reached on the prodSql server. Stopping retries.", + ); + reconnecting = false; + // 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"` - ); - } + 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) { + connected = false; + log.info( + //{ notify: true }, + { error: error }, + `${JSON.stringify( + error, + )}, "There was an error closing the sql connection"`, + ); + } };