feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration - Cache advisors for a week / allow them to refresh said cache
This commit is contained in:
@@ -21,6 +21,9 @@ const {
|
||||
const { GraphQLClient } = require("graphql-request");
|
||||
const queries = require("../graphql-client/queries");
|
||||
|
||||
// 1 week TTL for advisors cache
|
||||
const ADVISORS_CACHE_TTL = 7 * 24 * 60 * 60; // seconds
|
||||
|
||||
// ---------------- utils ----------------
|
||||
function resolveJobId(explicit, payload, job) {
|
||||
return explicit || payload?.jobId || payload?.jobid || job?.id || job?.jobId || job?.jobid || null;
|
||||
@@ -69,6 +72,20 @@ async function getBodyshopForSocket({ bodyshopId, socket }) {
|
||||
return bodyshop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build advisors cache namespace + field (per bodyshop + routing + department)
|
||||
*/
|
||||
function buildAdvisorsCacheNS({ bodyshopId, routing, departmentType = "B" }) {
|
||||
const dealer = routing?.dealerNumber || "unknown";
|
||||
const store = routing?.storeNumber || "none";
|
||||
const area = routing?.areaNumber || "none";
|
||||
const dept = (departmentType || "B").toUpperCase();
|
||||
return {
|
||||
ns: `rr:advisors:${bodyshopId}:${dealer}:${store}:${area}`,
|
||||
field: `dept:${dept}`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* VIN + Full Name merge (export flow)
|
||||
*/
|
||||
@@ -114,7 +131,9 @@ async function rrMultiCustomerSearch({ bodyshop, job, socket, redisHelpers }) {
|
||||
blocks,
|
||||
defaultRRTTL
|
||||
);
|
||||
} catch {}
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
const norm = normalizeCustomerCandidates(res, { ownersSet });
|
||||
@@ -158,17 +177,74 @@ function registerRREvents({ socket, redisHelpers }) {
|
||||
}
|
||||
});
|
||||
|
||||
// ---------- Advisors ----------
|
||||
// ---------- Advisors (cached) ----------
|
||||
socket.on("rr-get-advisors", async (args = {}, ack) => {
|
||||
const refresh = !!args?.refresh;
|
||||
const requestedDept = (args?.departmentType || "B").toUpperCase();
|
||||
|
||||
try {
|
||||
const { bodyshopId } = await getSessionOrSocket(redisHelpers, socket);
|
||||
const bodyshop = await getBodyshopForSocket({ bodyshopId, socket });
|
||||
CreateRRLogEvent(socket, "DEBUG", "rr-get-advisors: begin", { args });
|
||||
const res = await rrGetAdvisors(bodyshop, args);
|
||||
ack?.({ ok: true, result: res });
|
||||
socket.emit("rr-get-advisors:result", res);
|
||||
|
||||
// Build routing to bind cache key to bodyshop + dealer/store/area
|
||||
const { client, opts } = await buildClientAndOpts(bodyshop);
|
||||
const routing = opts?.routing || client?.opts?.routing || {};
|
||||
if (!routing?.dealerNumber) {
|
||||
throw new Error("rr-get-advisors: routing.dealerNumber required");
|
||||
}
|
||||
|
||||
const { ns, field } = buildAdvisorsCacheNS({
|
||||
bodyshopId,
|
||||
routing,
|
||||
departmentType: requestedDept
|
||||
});
|
||||
|
||||
let result = null;
|
||||
let fromCache = false;
|
||||
|
||||
// 1) Try cache (unless forced refresh)
|
||||
if (!refresh) {
|
||||
try {
|
||||
const cached = await redisHelpers.getProviderCache(ns, field);
|
||||
if (cached && Array.isArray(cached)) {
|
||||
result = cached;
|
||||
fromCache = true;
|
||||
CreateRRLogEvent(socket, "DEBUG", "rr-get-advisors: cache hit", {
|
||||
ns,
|
||||
field,
|
||||
count: cached.length,
|
||||
ttl: ADVISORS_CACHE_TTL
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
CreateRRLogEvent(socket, "WARN", "rr-get-advisors: cache read failed", { ns, field, error: e?.message });
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Fetch + cache when no cache or forced refresh
|
||||
if (!result) {
|
||||
const live = await rrGetAdvisors(bodyshop, { departmentType: requestedDept });
|
||||
result = Array.isArray(live) ? live : [];
|
||||
try {
|
||||
await redisHelpers.setProviderCache(ns, field, result, ADVISORS_CACHE_TTL);
|
||||
CreateRRLogEvent(socket, "DEBUG", "rr-get-advisors: cache populated", {
|
||||
ns,
|
||||
field,
|
||||
count: result.length,
|
||||
ttl: ADVISORS_CACHE_TTL
|
||||
});
|
||||
} catch (e) {
|
||||
CreateRRLogEvent(socket, "WARN", "rr-get-advisors: cache write failed", { ns, field, error: e?.message });
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Respond
|
||||
ack?.({ ok: true, result, fromCache });
|
||||
socket.emit("rr-get-advisors:result", { result, fromCache });
|
||||
CreateRRLogEvent(socket, "DEBUG", "rr-get-advisors: success", {
|
||||
count: Array.isArray(res) ? res.length : undefined
|
||||
count: Array.isArray(result) ? result.length : undefined,
|
||||
fromCache
|
||||
});
|
||||
} catch (err) {
|
||||
CreateRRLogEvent(socket, "ERROR", "rr-get-advisors: failed", { error: err?.message });
|
||||
@@ -255,7 +331,9 @@ function registerRREvents({ socket, redisHelpers }) {
|
||||
});
|
||||
try {
|
||||
socket.emit("export-failed", { vendor: "rr", jobId: rid, error: error.message });
|
||||
} catch {}
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -307,9 +385,11 @@ function registerRREvents({ socket, redisHelpers }) {
|
||||
blocksVin,
|
||||
defaultRRTTL
|
||||
);
|
||||
} catch {}
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
const ownersSet = ownersFromVinBlocks(blocksVin, job.v_vin);
|
||||
if (ownersSet && ownersSet.size) {
|
||||
if (ownersSet?.size) {
|
||||
const sel = String(selectedCustNo);
|
||||
if (!ownersSet.has(sel)) {
|
||||
const [existingOwner] = Array.from(ownersSet).map(String);
|
||||
@@ -327,7 +407,9 @@ function registerRREvents({ socket, redisHelpers }) {
|
||||
message:
|
||||
"VIN already exists in RR under a different customer. Using the VIN's owner to continue the export."
|
||||
});
|
||||
} catch {}
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
selectedCustNo = existingOwner;
|
||||
}
|
||||
}
|
||||
@@ -452,7 +534,9 @@ function registerRREvents({ socket, redisHelpers }) {
|
||||
});
|
||||
try {
|
||||
socket.emit("export-failed", { vendor: "rr", jobId: rid, error: error.message });
|
||||
} catch {}
|
||||
} catch {
|
||||
//
|
||||
}
|
||||
ack?.({ ok: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user