refactor(sql): corrections to the way we reconnect so the app can error out and be reactivated later
This commit is contained in:
44
backend/db/schema/printers.schema.ts
Normal file
44
backend/db/schema/printers.schema.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
boolean,
|
||||||
|
integer,
|
||||||
|
jsonb,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uniqueIndex,
|
||||||
|
uuid,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import type z from "zod";
|
||||||
|
|
||||||
|
export const printerData = pgTable(
|
||||||
|
"printer_data",
|
||||||
|
{
|
||||||
|
id: uuid("id").defaultRandom().primaryKey(),
|
||||||
|
humanReadableId: text("humanReadable_id").unique().notNull(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
ipAddress: text("ipAddress"),
|
||||||
|
port: integer("port"),
|
||||||
|
status: text("status"),
|
||||||
|
statusText: text("statusText"),
|
||||||
|
printerSN: text("printer_sn"),
|
||||||
|
lastTimePrinted: timestamp("last_time_printed").notNull().defaultNow(),
|
||||||
|
assigned: boolean("assigned").default(false),
|
||||||
|
remark: text("remark"),
|
||||||
|
printDelay: integer("printDelay").default(90),
|
||||||
|
processes: jsonb("processes").default([]),
|
||||||
|
printDelayOverride: boolean("print_delay_override").default(false), // this will be more for if we have the lot time active but want to over ride this single line for some reason
|
||||||
|
add_Date: timestamp("add_Date").defaultNow(),
|
||||||
|
upd_date: timestamp("upd_date").defaultNow(),
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
//uniqueIndex("emailUniqueIndex").on(sql`lower(${table.email})`),
|
||||||
|
uniqueIndex("printer_id").on(table.humanReadableId),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
export const printerSchema = createSelectSchema(printerData);
|
||||||
|
export const newPrinterSchema = createInsertSchema(printerData);
|
||||||
|
|
||||||
|
export type Printer = z.infer<typeof printerSchema>;
|
||||||
|
export type NewPrinter = z.infer<typeof newPrinterSchema>;
|
||||||
@@ -7,12 +7,17 @@ import { returnFunc } from "../utils/returnHelper.utils.js";
|
|||||||
export let pool2: sql.ConnectionPool;
|
export let pool2: sql.ConnectionPool;
|
||||||
export let connected: boolean = false;
|
export let connected: boolean = false;
|
||||||
export let reconnecting = false;
|
export let reconnecting = false;
|
||||||
|
// start the delay out as 2 seconds
|
||||||
|
let delayStart = 2000;
|
||||||
|
let attempt = 0;
|
||||||
|
const maxAttempts = 10;
|
||||||
|
|
||||||
export const connectGPSql = async () => {
|
export const connectGPSql = async () => {
|
||||||
const serverUp = await checkHostnamePort(`USMCD1VMS011:1433`);
|
const serverUp = await checkHostnamePort(`USMCD1VMS011:1433`);
|
||||||
if (!serverUp) {
|
if (!serverUp) {
|
||||||
// we will try to reconnect
|
// we will try to reconnect
|
||||||
connected = false;
|
connected = false;
|
||||||
|
reconnectToSql;
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
level: "error",
|
level: "error",
|
||||||
@@ -48,6 +53,7 @@ export const connectGPSql = async () => {
|
|||||||
notify: false,
|
notify: false,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
reconnectToSql;
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
level: "error",
|
level: "error",
|
||||||
@@ -104,11 +110,6 @@ export const reconnectToSql = async () => {
|
|||||||
//set reconnecting to true while we try to reconnect
|
//set reconnecting to true while we try to reconnect
|
||||||
reconnecting = true;
|
reconnecting = true;
|
||||||
|
|
||||||
// start the delay out as 2 seconds
|
|
||||||
let delayStart = 2000;
|
|
||||||
let attempt = 0;
|
|
||||||
const maxAttempts = 10;
|
|
||||||
|
|
||||||
while (!connected && attempt < maxAttempts) {
|
while (!connected && attempt < maxAttempts) {
|
||||||
attempt++;
|
attempt++;
|
||||||
log.info(
|
log.info(
|
||||||
@@ -121,7 +122,7 @@ export const reconnectToSql = async () => {
|
|||||||
|
|
||||||
if (!serverUp) {
|
if (!serverUp) {
|
||||||
delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
|
delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -131,19 +132,11 @@ export const reconnectToSql = async () => {
|
|||||||
log.info(`${gpSqlConfig.server} is connected to ${gpSqlConfig.database}`);
|
log.info(`${gpSqlConfig.server} is connected to ${gpSqlConfig.database}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
delayStart = Math.min(delayStart * 2, 30000);
|
delayStart = Math.min(delayStart * 2, 30000);
|
||||||
return returnFunc({
|
log.error({ error }, "Failed to reconnect to the prod sql server.");
|
||||||
success: false,
|
|
||||||
level: "error",
|
|
||||||
module: "system",
|
|
||||||
subModule: "db",
|
|
||||||
message: "Failed to reconnect to the prod sql server.",
|
|
||||||
data: [error],
|
|
||||||
notify: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connected) {
|
if (!connected && attempt >= maxAttempts) {
|
||||||
log.error(
|
log.error(
|
||||||
{ notify: true },
|
{ notify: true },
|
||||||
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||||
import {
|
import { connected, pool2 } from "./gpSqlConnection.controller.js";
|
||||||
connected,
|
|
||||||
pool2,
|
|
||||||
reconnecting,
|
|
||||||
reconnectToSql,
|
|
||||||
} from "./gpSqlConnection.controller.js";
|
|
||||||
|
|
||||||
interface SqlError extends Error {
|
interface SqlError extends Error {
|
||||||
code?: string;
|
code?: string;
|
||||||
@@ -22,29 +17,15 @@ interface SqlError extends Error {
|
|||||||
*/
|
*/
|
||||||
export const gpQuery = async (queryToRun: string, name: string) => {
|
export const gpQuery = async (queryToRun: string, name: string) => {
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
reconnectToSql();
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
if (reconnecting) {
|
level: "error",
|
||||||
return returnFunc({
|
module: "system",
|
||||||
success: false,
|
subModule: "gpSql",
|
||||||
level: "error",
|
message: `${process.env.PROD_PLANT_TOKEN} is offline or attempting to reconnect`,
|
||||||
module: "system",
|
data: [],
|
||||||
subModule: "gpSql",
|
notify: false,
|
||||||
message: `The sql ${process.env.PROD_PLANT_TOKEN} is trying to reconnect already`,
|
});
|
||||||
data: [],
|
|
||||||
notify: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return returnFunc({
|
|
||||||
success: false,
|
|
||||||
level: "error",
|
|
||||||
module: "system",
|
|
||||||
subModule: "gpSql",
|
|
||||||
message: `${process.env.PROD_PLANT_TOKEN} is not connected, and failed to connect.`,
|
|
||||||
data: [],
|
|
||||||
notify: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//change to the correct server
|
//change to the correct server
|
||||||
|
|||||||
@@ -7,12 +7,17 @@ import { returnFunc } from "../utils/returnHelper.utils.js";
|
|||||||
export let pool: sql.ConnectionPool;
|
export let pool: sql.ConnectionPool;
|
||||||
export let connected: boolean = false;
|
export let connected: boolean = false;
|
||||||
export let reconnecting = false;
|
export let reconnecting = false;
|
||||||
|
// start the delay out as 2 seconds
|
||||||
|
let delayStart = 2000;
|
||||||
|
let attempt = 0;
|
||||||
|
const maxAttempts = 10;
|
||||||
|
|
||||||
export const connectProdSql = async () => {
|
export const connectProdSql = async () => {
|
||||||
const serverUp = await checkHostnamePort(`${process.env.PROD_SERVER}:1433`);
|
const serverUp = await checkHostnamePort(`${process.env.PROD_SERVER}:1433`);
|
||||||
if (!serverUp) {
|
if (!serverUp) {
|
||||||
// we will try to reconnect
|
// we will try to reconnect
|
||||||
connected = false;
|
connected = false;
|
||||||
|
reconnectToSql();
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
level: "error",
|
level: "error",
|
||||||
@@ -48,6 +53,7 @@ export const connectProdSql = async () => {
|
|||||||
notify: false,
|
notify: false,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
reconnectToSql();
|
||||||
return returnFunc({
|
return returnFunc({
|
||||||
success: false,
|
success: false,
|
||||||
level: "error",
|
level: "error",
|
||||||
@@ -104,11 +110,6 @@ export const reconnectToSql = async () => {
|
|||||||
//set reconnecting to true while we try to reconnect
|
//set reconnecting to true while we try to reconnect
|
||||||
reconnecting = true;
|
reconnecting = true;
|
||||||
|
|
||||||
// start the delay out as 2 seconds
|
|
||||||
let delayStart = 2000;
|
|
||||||
let attempt = 0;
|
|
||||||
const maxAttempts = 10;
|
|
||||||
|
|
||||||
while (!connected && attempt < maxAttempts) {
|
while (!connected && attempt < maxAttempts) {
|
||||||
attempt++;
|
attempt++;
|
||||||
log.info(
|
log.info(
|
||||||
@@ -121,7 +122,7 @@ export const reconnectToSql = async () => {
|
|||||||
|
|
||||||
if (!serverUp) {
|
if (!serverUp) {
|
||||||
delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
|
delayStart = Math.min(delayStart * 2, 30000); // exponential backoff until up to 30000
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -133,19 +134,12 @@ export const reconnectToSql = async () => {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
delayStart = Math.min(delayStart * 2, 30000);
|
delayStart = Math.min(delayStart * 2, 30000);
|
||||||
return returnFunc({
|
delayStart = Math.min(delayStart * 2, 30000);
|
||||||
success: false,
|
log.error({ error }, "Failed to reconnect to the prod sql server.");
|
||||||
level: "error",
|
|
||||||
module: "system",
|
|
||||||
subModule: "db",
|
|
||||||
message: "Failed to reconnect to the prod sql server.",
|
|
||||||
data: [error],
|
|
||||||
notify: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connected) {
|
if (!connected && attempt >= maxAttempts) {
|
||||||
log.error(
|
log.error(
|
||||||
{ notify: true },
|
{ notify: true },
|
||||||
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
"Max reconnect attempts reached on the prodSql server. Stopping retries.",
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||||
import {
|
import { connected, pool } from "./prodSqlConnection.controller.js";
|
||||||
connected,
|
|
||||||
pool,
|
|
||||||
reconnecting,
|
|
||||||
reconnectToSql,
|
|
||||||
} from "./prodSqlConnection.controller.js";
|
|
||||||
|
|
||||||
interface SqlError extends Error {
|
interface SqlError extends Error {
|
||||||
code?: string;
|
code?: string;
|
||||||
@@ -22,29 +17,15 @@ interface SqlError extends Error {
|
|||||||
*/
|
*/
|
||||||
export const prodQuery = async (queryToRun: string, name: string) => {
|
export const prodQuery = async (queryToRun: string, name: string) => {
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
reconnectToSql();
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
if (reconnecting) {
|
level: "error",
|
||||||
return returnFunc({
|
module: "system",
|
||||||
success: false,
|
subModule: "prodSql",
|
||||||
level: "error",
|
message: `${process.env.PROD_PLANT_TOKEN} is offline or attempting to reconnect`,
|
||||||
module: "system",
|
data: [],
|
||||||
subModule: "prodSql",
|
notify: false,
|
||||||
message: `The sql ${process.env.PROD_PLANT_TOKEN} is trying to reconnect already`,
|
});
|
||||||
data: [],
|
|
||||||
notify: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return returnFunc({
|
|
||||||
success: false,
|
|
||||||
level: "error",
|
|
||||||
module: "system",
|
|
||||||
subModule: "prodSql",
|
|
||||||
message: `${process.env.PROD_PLANT_TOKEN} is not connected, and failed to connect.`,
|
|
||||||
data: [],
|
|
||||||
notify: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//change to the correct server
|
//change to the correct server
|
||||||
|
|||||||
124
backend/utils/prodEndpoint.utils.ts
Normal file
124
backend/utils/prodEndpoint.utils.ts
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import https from "node:https";
|
||||||
|
import axios from "axios";
|
||||||
|
import { returnFunc } from "./returnHelper.utils.js";
|
||||||
|
import { tryCatch } from "./trycatch.utils.js";
|
||||||
|
|
||||||
|
type bodyData = any;
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
endpoint: string;
|
||||||
|
data?: bodyData[];
|
||||||
|
method: "post" | "get" | "delete" | "patch";
|
||||||
|
};
|
||||||
|
|
||||||
|
// type ApiResponse<T = unknown> = {
|
||||||
|
// status: number;
|
||||||
|
// statusText: string;
|
||||||
|
// data: T;
|
||||||
|
// };
|
||||||
|
|
||||||
|
// create the test server stuff
|
||||||
|
const testServers = [
|
||||||
|
{ token: "test1", port: 8940 },
|
||||||
|
{ token: "test2", port: 8941 },
|
||||||
|
{ token: "test3", port: 8942 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const agent = new https.Agent({
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const prodEndpointCreation = async (endpoint: string) => {
|
||||||
|
let url = "";
|
||||||
|
//get the plant token
|
||||||
|
const plantToken = process.env.PROD_PLANT_TOKEN ?? "test1";
|
||||||
|
|
||||||
|
// check if we are a test server
|
||||||
|
const testServer = testServers.some((server) => server.token === plantToken);
|
||||||
|
|
||||||
|
// await db
|
||||||
|
// .select()
|
||||||
|
// .from(settings)
|
||||||
|
// .where(eq(settings.name, "dbServer"));
|
||||||
|
|
||||||
|
if (testServer) {
|
||||||
|
//filter out what testserver we are
|
||||||
|
const test = testServers.filter((t) => t.token === plantToken);
|
||||||
|
// "https://usmcd1vms036.alpla.net:8942/application/public/v1.0/DemandManagement/ORDERS"
|
||||||
|
url = `https://${process.env.PROD_SERVER}.alpla.net:${test[0]?.port}/application${endpoint}`;
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
|
url = `https://${plantToken}prod.alpla.net/application${endpoint}`;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param timeoutDelay
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const runProdApi = async (data: Data) => {
|
||||||
|
const url = await prodEndpointCreation(data.endpoint);
|
||||||
|
|
||||||
|
const { data: d, error } = await tryCatch(
|
||||||
|
axios({
|
||||||
|
method: data.method as string,
|
||||||
|
url,
|
||||||
|
data: data.data ? data.data[0] : undefined,
|
||||||
|
headers: {
|
||||||
|
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
validateStatus: () => true,
|
||||||
|
httpsAgent: agent,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (d?.status) {
|
||||||
|
case 200:
|
||||||
|
return returnFunc({
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "utils",
|
||||||
|
subModule: "prodEndpoint",
|
||||||
|
message: "Data from prod endpoint",
|
||||||
|
data: d.data,
|
||||||
|
notify: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
case 401:
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "utils",
|
||||||
|
subModule: "prodEndpoint",
|
||||||
|
message: "Data from prod endpoint",
|
||||||
|
data: d.data,
|
||||||
|
notify: false,
|
||||||
|
});
|
||||||
|
case 400:
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "utils",
|
||||||
|
subModule: "prodEndpoint",
|
||||||
|
message: "Data from prod endpoint",
|
||||||
|
data: d.data,
|
||||||
|
notify: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return returnFunc({
|
||||||
|
success: true,
|
||||||
|
level: "error",
|
||||||
|
module: "utils",
|
||||||
|
subModule: "prodEndpoint",
|
||||||
|
message: "Failed to get data from the prod endpoint",
|
||||||
|
data: error as any,
|
||||||
|
notify: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
vars {
|
vars {
|
||||||
url: http://localhost:3000/lst
|
url: http://uslim1vms006:3100/lst
|
||||||
readerIp: 10.44.14.215
|
readerIp: 10.44.14.215
|
||||||
}
|
}
|
||||||
vars:secret [
|
vars:secret [
|
||||||
|
|||||||
Reference in New Issue
Block a user